Blender  V3.3
meshtools.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2004 Blender Foundation. All rights reserved. */
3 
11 #include "MEM_guardedalloc.h"
12 
13 #include "DNA_key_types.h"
14 #include "DNA_material_types.h"
15 #include "DNA_mesh_types.h"
16 #include "DNA_meshdata_types.h"
17 #include "DNA_modifier_types.h"
18 #include "DNA_object_types.h"
19 #include "DNA_scene_types.h"
20 #include "DNA_screen_types.h"
21 #include "DNA_view3d_types.h"
22 #include "DNA_workspace_types.h"
23 
24 #include "BKE_context.h"
25 #include "BKE_customdata.h"
26 #include "BKE_deform.h"
27 #include "BKE_editmesh.h"
28 #include "BKE_key.h"
29 #include "BKE_layer.h"
30 #include "BKE_lib_id.h"
31 #include "BKE_main.h"
32 #include "BKE_material.h"
33 #include "BKE_mesh.h"
34 #include "BKE_mesh_iterators.h"
35 #include "BKE_mesh_runtime.h"
36 #include "BKE_multires.h"
37 #include "BKE_object.h"
38 #include "BKE_object_deform.h"
39 #include "BKE_object_facemap.h"
40 #include "BKE_report.h"
41 
42 #include "DEG_depsgraph.h"
43 #include "DEG_depsgraph_build.h"
44 #include "DEG_depsgraph_query.h"
45 
46 #include "DRW_select_buffer.h"
47 
48 #include "ED_mesh.h"
49 #include "ED_object.h"
50 #include "ED_view3d.h"
51 
52 #include "WM_api.h"
53 #include "WM_types.h"
54 
55 /* * ********************** no editmode!!! *********** */
56 
57 /*********************** JOIN ***************************/
58 
59 /* join selected meshes into the active mesh, context sensitive
60  * return 0 if no join is made (error) and 1 if the join is done */
61 
63  Main *bmain,
64  Scene *scene,
65  Object *ob_dst,
66  Object *ob_src,
67  const float imat[4][4],
68  MVert **mvert_pp,
69  MEdge **medge_pp,
70  MLoop **mloop_pp,
71  MPoly **mpoly_pp,
72  CustomData *vdata,
73  CustomData *edata,
74  CustomData *ldata,
75  CustomData *pdata,
76  int totvert,
77  int totedge,
78  int totloop,
79  int totpoly,
80  Key *key,
81  Key *nkey,
82  Material **matar,
83  int *matmap,
84  int totcol,
85  int *vertofs,
86  int *edgeofs,
87  int *loopofs,
88  int *polyofs)
89 {
90  int a, b;
91 
92  Mesh *me = static_cast<Mesh *>(ob_src->data);
93  MVert *mvert = *mvert_pp;
94  MEdge *medge = *medge_pp;
95  MLoop *mloop = *mloop_pp;
96  MPoly *mpoly = *mpoly_pp;
97 
98  if (me->totvert) {
99  /* merge customdata flag */
100  ((Mesh *)ob_dst->data)->cd_flag |= me->cd_flag;
101 
102  /* standard data */
103  CustomData_merge(&me->vdata, vdata, CD_MASK_MESH.vmask, CD_DEFAULT, totvert);
104  CustomData_copy_data_named(&me->vdata, vdata, 0, *vertofs, me->totvert);
105 
106  /* vertex groups */
107  MDeformVert *dvert = (MDeformVert *)CustomData_get(vdata, *vertofs, CD_MDEFORMVERT);
108  const MDeformVert *dvert_src = (const MDeformVert *)CustomData_get(
109  &me->vdata, 0, CD_MDEFORMVERT);
110 
111  /* Remap to correct new vgroup indices, if needed. */
112  if (dvert_src) {
113  BLI_assert(dvert != nullptr);
114 
115  /* Build src to merged mapping of vgroup indices. */
116  int *vgroup_index_map;
117  int vgroup_index_map_len;
118  vgroup_index_map = BKE_object_defgroup_index_map_create(
119  ob_src, ob_dst, &vgroup_index_map_len);
121  dvert, me->totvert, vgroup_index_map, vgroup_index_map_len);
122  if (vgroup_index_map != nullptr) {
123  MEM_freeN(vgroup_index_map);
124  }
125  }
126 
127  /* if this is the object we're merging into, no need to do anything */
128  if (ob_src != ob_dst) {
129  float cmat[4][4];
130 
131  /* Watch this: switch matrix multiplication order really goes wrong. */
132  mul_m4_m4m4(cmat, imat, ob_src->obmat);
133 
134  /* transform vertex coordinates into new space */
135  for (a = 0; a < me->totvert; a++, mvert++) {
136  mul_m4_v3(cmat, mvert->co);
137  }
138 
139  /* For each shape-key in destination mesh:
140  * - if there's a matching one, copy it across
141  * (will need to transform vertices into new space...).
142  * - otherwise, just copy own coordinates of mesh
143  * (no need to transform vertex coordinates into new space).
144  */
145  if (key) {
146  /* if this mesh has any shape-keys, check first, otherwise just copy coordinates */
147  LISTBASE_FOREACH (KeyBlock *, kb, &key->block) {
148  /* get pointer to where to write data for this mesh in shape-key's data array */
149  float(*cos)[3] = ((float(*)[3])kb->data) + *vertofs;
150 
151  /* Check if this mesh has such a shape-key. */
152  KeyBlock *okb = me->key ? BKE_keyblock_find_name(me->key, kb->name) : nullptr;
153  if (okb) {
154  /* copy this mesh's shape-key to the destination shape-key
155  * (need to transform first) */
156  float(*ocos)[3] = static_cast<float(*)[3]>(okb->data);
157  for (a = 0; a < me->totvert; a++, cos++, ocos++) {
158  copy_v3_v3(*cos, *ocos);
159  mul_m4_v3(cmat, *cos);
160  }
161  }
162  else {
163  /* Copy this mesh's vertex coordinates to the destination shape-key. */
164  for (a = 0, mvert = *mvert_pp; a < me->totvert; a++, cos++, mvert++) {
165  copy_v3_v3(*cos, mvert->co);
166  }
167  }
168  }
169  }
170  }
171  else {
172  /* for each shape-key in destination mesh:
173  * - if it was an 'original', copy the appropriate data from nkey
174  * - otherwise, copy across plain coordinates (no need to transform coordinates)
175  */
176  if (key) {
177  LISTBASE_FOREACH (KeyBlock *, kb, &key->block) {
178  /* get pointer to where to write data for this mesh in shape-key's data array */
179  float(*cos)[3] = ((float(*)[3])kb->data) + *vertofs;
180 
181  /* Check if this was one of the original shape-keys. */
182  KeyBlock *okb = nkey ? BKE_keyblock_find_name(nkey, kb->name) : nullptr;
183  if (okb) {
184  /* copy this mesh's shape-key to the destination shape-key */
185  float(*ocos)[3] = static_cast<float(*)[3]>(okb->data);
186  for (a = 0; a < me->totvert; a++, cos++, ocos++) {
187  copy_v3_v3(*cos, *ocos);
188  }
189  }
190  else {
191  /* Copy base-coordinates to the destination shape-key. */
192  for (a = 0, mvert = *mvert_pp; a < me->totvert; a++, cos++, mvert++) {
193  copy_v3_v3(*cos, mvert->co);
194  }
195  }
196  }
197  }
198  }
199  }
200 
201  if (me->totedge) {
202  CustomData_merge(&me->edata, edata, CD_MASK_MESH.emask, CD_DEFAULT, totedge);
203  CustomData_copy_data_named(&me->edata, edata, 0, *edgeofs, me->totedge);
204 
205  for (a = 0; a < me->totedge; a++, medge++) {
206  medge->v1 += *vertofs;
207  medge->v2 += *vertofs;
208  }
209  }
210 
211  if (me->totloop) {
212  if (ob_src != ob_dst) {
214 
216 
217  if ((mmd = get_multires_modifier(scene, ob_src, true))) {
219  bmain, ob_src, true, ED_object_multires_update_totlevels_cb, &mmd->totlvl);
220  }
221  }
222 
223  CustomData_merge(&me->ldata, ldata, CD_MASK_MESH.lmask, CD_DEFAULT, totloop);
224  CustomData_copy_data_named(&me->ldata, ldata, 0, *loopofs, me->totloop);
225 
226  for (a = 0; a < me->totloop; a++, mloop++) {
227  mloop->v += *vertofs;
228  mloop->e += *edgeofs;
229  }
230  }
231 
232  if (me->totpoly) {
233  if (matmap) {
234  /* make mapping for materials */
235  for (a = 1; a <= ob_src->totcol; a++) {
236  Material *ma = BKE_object_material_get(ob_src, a);
237 
238  for (b = 0; b < totcol; b++) {
239  if (ma == matar[b]) {
240  matmap[a - 1] = b;
241  break;
242  }
243  }
244  }
245  }
246 
247  CustomData_merge(&me->pdata, pdata, CD_MASK_MESH.pmask, CD_DEFAULT, totpoly);
248  CustomData_copy_data_named(&me->pdata, pdata, 0, *polyofs, me->totpoly);
249 
250  for (a = 0; a < me->totpoly; a++, mpoly++) {
251  mpoly->loopstart += *loopofs;
252  mpoly->mat_nr = matmap ? matmap[mpoly->mat_nr] : 0;
253  }
254 
255  /* Face maps. */
256  int *fmap = (int *)CustomData_get(pdata, *polyofs, CD_FACEMAP);
257  const int *fmap_src = (const int *)CustomData_get(&me->pdata, 0, CD_FACEMAP);
258 
259  /* Remap to correct new face-map indices, if needed. */
260  if (fmap_src) {
261  BLI_assert(fmap != nullptr);
262  int *fmap_index_map;
263  int fmap_index_map_len;
264  fmap_index_map = BKE_object_facemap_index_map_create(ob_src, ob_dst, &fmap_index_map_len);
265  BKE_object_facemap_index_map_apply(fmap, me->totpoly, fmap_index_map, fmap_index_map_len);
266  if (fmap_index_map != nullptr) {
267  MEM_freeN(fmap_index_map);
268  }
269  }
270  }
271 
272  /* these are used for relinking (cannot be set earlier, or else reattaching goes wrong) */
273  *vertofs += me->totvert;
274  *mvert_pp += me->totvert;
275  *edgeofs += me->totedge;
276  *medge_pp += me->totedge;
277  *loopofs += me->totloop;
278  *mloop_pp += me->totloop;
279  *polyofs += me->totpoly;
280  *mpoly_pp += me->totpoly;
281 }
282 
283 /* Face Sets IDs are a sparse sequence, so this function offsets all the IDs by face_set_offset and
284  * updates face_set_offset with the maximum ID value. This way, when used in multiple meshes, all
285  * of them will have different IDs for their Face Sets. */
286 static void mesh_join_offset_face_sets_ID(const Mesh *mesh, int *face_set_offset)
287 {
288  if (!mesh->totpoly) {
289  return;
290  }
291 
292  int *face_sets = (int *)CustomData_get_layer(&mesh->pdata, CD_SCULPT_FACE_SETS);
293  if (!face_sets) {
294  return;
295  }
296 
297  int max_face_set = 0;
298  for (int f = 0; f < mesh->totpoly; f++) {
299  /* As face sets encode the visibility in the integer sign, the offset needs to be added or
300  * subtracted depending on the initial sign of the integer to get the new ID. */
301  if (abs(face_sets[f]) <= *face_set_offset) {
302  if (face_sets[f] > 0) {
303  face_sets[f] += *face_set_offset;
304  }
305  else {
306  face_sets[f] -= *face_set_offset;
307  }
308  }
309  max_face_set = max_ii(max_face_set, abs(face_sets[f]));
310  }
311  *face_set_offset = max_face_set;
312 }
313 
315 {
316  Main *bmain = CTX_data_main(C);
319  Material **matar = nullptr, *ma;
320  Mesh *me;
321  MVert *mvert = nullptr;
322  MEdge *medge = nullptr;
323  MPoly *mpoly = nullptr;
324  MLoop *mloop = nullptr;
325  Key *key, *nkey = nullptr;
326  float imat[4][4];
327  int a, b, totcol, totmat = 0, totedge = 0, totvert = 0;
328  int totloop = 0, totpoly = 0, vertofs, *matmap = nullptr;
329  int i, haskey = 0, edgeofs, loopofs, polyofs;
330  bool ok = false, join_parent = false;
331  CustomData vdata, edata, fdata, ldata, pdata;
332 
333  if (ob->mode & OB_MODE_EDIT) {
334  BKE_report(op->reports, RPT_WARNING, "Cannot join while in edit mode");
335  return OPERATOR_CANCELLED;
336  }
337 
338  /* ob is the object we are adding geometry to */
339  if (!ob || ob->type != OB_MESH) {
340  BKE_report(op->reports, RPT_WARNING, "Active object is not a mesh");
341  return OPERATOR_CANCELLED;
342  }
343 
345 
346  /* count & check */
347  CTX_DATA_BEGIN (C, Object *, ob_iter, selected_editable_objects) {
348  if (ob_iter->type == OB_MESH) {
349  me = static_cast<Mesh *>(ob_iter->data);
350 
351  totvert += me->totvert;
352  totedge += me->totedge;
353  totloop += me->totloop;
354  totpoly += me->totpoly;
355  totmat += ob_iter->totcol;
356 
357  if (ob_iter == ob) {
358  ok = true;
359  }
360 
361  if ((ob->parent != nullptr) && (ob_iter == ob->parent)) {
362  join_parent = true;
363  }
364 
365  /* Check for shape-keys. */
366  if (me->key) {
367  haskey++;
368  }
369  }
370  }
371  CTX_DATA_END;
372 
373  /* Apply parent transform if the active object's parent was joined to it.
374  * NOTE: This doesn't apply recursive parenting. */
375  if (join_parent) {
376  ob->parent = nullptr;
377  BKE_object_apply_mat4_ex(ob, ob->obmat, ob->parent, ob->parentinv, false);
378  }
379 
380  /* that way the active object is always selected */
381  if (ok == false) {
382  BKE_report(op->reports, RPT_WARNING, "Active object is not a selected mesh");
383  return OPERATOR_CANCELLED;
384  }
385 
386  /* Only join meshes if there are verts to join,
387  * there aren't too many, and we only had one mesh selected. */
388  me = (Mesh *)ob->data;
389  key = me->key;
390 
391  if (ELEM(totvert, 0, me->totvert)) {
392  BKE_report(op->reports, RPT_WARNING, "No mesh data to join");
393  return OPERATOR_CANCELLED;
394  }
395 
396  if (totvert > MESH_MAX_VERTS) {
397  BKE_reportf(op->reports,
398  RPT_WARNING,
399  "Joining results in %d vertices, limit is %ld",
400  totvert,
402  return OPERATOR_CANCELLED;
403  }
404 
405  /* remove tessface to ensure we don't hold references to invalid faces */
407 
408  /* Clear any run-time data.
409  * Even though this mesh wont typically have run-time data, the Python API can for e.g.
410  * create loop-triangle cache here, which is confusing when left in the mesh, see: T90798. */
413 
414  /* new material indices and material array */
415  if (totmat) {
416  matar = static_cast<Material **>(MEM_callocN(sizeof(*matar) * totmat, __func__));
417  matmap = static_cast<int *>(MEM_callocN(sizeof(*matmap) * totmat, __func__));
418  }
419  totcol = ob->totcol;
420 
421  /* Active object materials in new main array, is nicer start! */
422  for (a = 0; a < ob->totcol; a++) {
423  matar[a] = BKE_object_material_get(ob, a + 1);
424  id_us_plus((ID *)matar[a]);
425  /* increase id->us : will be lowered later */
426  }
427 
428  /* - If destination mesh had shape-keys, move them somewhere safe, and set up placeholders
429  * with arrays that are large enough to hold shape-key data for all meshes.
430  * - If destination mesh didn't have shape-keys, but we encountered some in the meshes we're
431  * joining, set up a new key-block and assign to the mesh.
432  */
433  if (key) {
434  /* make a duplicate copy that will only be used here... (must remember to free it!) */
435  nkey = (Key *)BKE_id_copy(bmain, &key->id);
436 
437  /* for all keys in old block, clear data-arrays */
438  LISTBASE_FOREACH (KeyBlock *, kb, &key->block) {
439  if (kb->data) {
440  MEM_freeN(kb->data);
441  }
442  kb->data = MEM_callocN(sizeof(float[3]) * totvert, "join_shapekey");
443  kb->totelem = totvert;
444  }
445  }
446  else if (haskey) {
447  /* add a new key-block and add to the mesh */
448  key = me->key = BKE_key_add(bmain, (ID *)me);
449  key->type = KEY_RELATIVE;
450  }
451 
452  /* Update face_set_id_offset with the face set data in the active object first. This way the Face
453  * Sets IDs in the active object are not the ones that are modified. */
454  Mesh *mesh_active = BKE_mesh_from_object(ob);
455  int face_set_id_offset = 0;
456  mesh_join_offset_face_sets_ID(mesh_active, &face_set_id_offset);
457 
458  /* Copy materials, vertex-groups, face sets & face-maps across objects. */
459  CTX_DATA_BEGIN (C, Object *, ob_iter, selected_editable_objects) {
460  /* only act if a mesh, and not the one we're joining to */
461  if ((ob != ob_iter) && (ob_iter->type == OB_MESH)) {
462  me = static_cast<Mesh *>(ob_iter->data);
463 
464  /* Join this object's vertex groups to the base one's */
466  /* See if this group exists in the object (if it doesn't, add it to the end) */
467  if (!BKE_object_defgroup_find_name(ob, dg->name)) {
468  bDeformGroup *odg = static_cast<bDeformGroup *>(
469  MEM_mallocN(sizeof(bDeformGroup), __func__));
470  memcpy(odg, dg, sizeof(bDeformGroup));
471  BLI_addtail(&mesh_active->vertex_group_names, odg);
472  }
473  }
474  if (!BLI_listbase_is_empty(&mesh_active->vertex_group_names) &&
475  me->vertex_group_active_index == 0) {
477  }
478 
479  /* Join this object's face maps to the base one's. */
480  LISTBASE_FOREACH (bFaceMap *, fmap, &ob_iter->fmaps) {
481  /* See if this group exists in the object (if it doesn't, add it to the end) */
482  if (BKE_object_facemap_find_name(ob, fmap->name) == nullptr) {
483  bFaceMap *fmap_new = static_cast<bFaceMap *>(MEM_mallocN(sizeof(bFaceMap), __func__));
484  memcpy(fmap_new, fmap, sizeof(bFaceMap));
485  BLI_addtail(&ob->fmaps, fmap_new);
486  }
487  }
488  if (ob->fmaps.first && ob->actfmap == 0) {
489  ob->actfmap = 1;
490  }
491 
492  mesh_join_offset_face_sets_ID(me, &face_set_id_offset);
493 
494  if (me->totvert) {
495  /* Add this object's materials to the base one's if they don't exist already
496  * (but only if limits not exceeded yet) */
497  if (totcol < MAXMAT) {
498  for (a = 1; a <= ob_iter->totcol; a++) {
499  ma = BKE_object_material_get(ob_iter, a);
500 
501  for (b = 0; b < totcol; b++) {
502  if (ma == matar[b]) {
503  break;
504  }
505  }
506  if (b == totcol) {
507  matar[b] = ma;
508  if (ma) {
509  id_us_plus(&ma->id);
510  }
511  totcol++;
512  }
513  if (totcol >= MAXMAT) {
514  break;
515  }
516  }
517  }
518 
519  /* If this mesh has shape-keys,
520  * check if destination mesh already has matching entries too. */
521  if (me->key && key) {
522  /* for remapping KeyBlock.relative */
523  int *index_map = static_cast<int *>(
524  MEM_mallocN(sizeof(int) * me->key->totkey, __func__));
525  KeyBlock **kb_map = static_cast<KeyBlock **>(
526  MEM_mallocN(sizeof(KeyBlock *) * me->key->totkey, __func__));
527 
528  LISTBASE_FOREACH_INDEX (KeyBlock *, kb, &me->key->block, i) {
529  BLI_assert(i < me->key->totkey);
530 
531  KeyBlock *kbn = BKE_keyblock_find_name(key, kb->name);
532  /* if key doesn't exist in destination mesh, add it */
533  if (kbn) {
534  index_map[i] = BLI_findindex(&key->block, kbn);
535  }
536  else {
537  index_map[i] = key->totkey;
538 
539  kbn = BKE_keyblock_add(key, kb->name);
540 
542 
543  /* adjust settings to fit (allocate a new data-array) */
544  kbn->data = MEM_callocN(sizeof(float[3]) * totvert, "joined_shapekey");
545  kbn->totelem = totvert;
546  }
547 
548  kb_map[i] = kbn;
549  }
550 
551  /* remap relative index values */
552  LISTBASE_FOREACH_INDEX (KeyBlock *, kb, &me->key->block, i) {
553  /* sanity check, should always be true */
554  if (LIKELY(kb->relative < me->key->totkey)) {
555  kb_map[i]->relative = index_map[kb->relative];
556  }
557  }
558 
559  MEM_freeN(index_map);
560  MEM_freeN(kb_map);
561  }
562  }
563  }
564  }
565  CTX_DATA_END;
566 
567  /* setup new data for destination mesh */
568  CustomData_reset(&vdata);
569  CustomData_reset(&edata);
570  CustomData_reset(&fdata);
571  CustomData_reset(&ldata);
572  CustomData_reset(&pdata);
573 
574  mvert = (MVert *)CustomData_add_layer(&vdata, CD_MVERT, CD_CALLOC, nullptr, totvert);
575  medge = (MEdge *)CustomData_add_layer(&edata, CD_MEDGE, CD_CALLOC, nullptr, totedge);
576  mloop = (MLoop *)CustomData_add_layer(&ldata, CD_MLOOP, CD_CALLOC, nullptr, totloop);
577  mpoly = (MPoly *)CustomData_add_layer(&pdata, CD_MPOLY, CD_CALLOC, nullptr, totpoly);
578 
579  vertofs = 0;
580  edgeofs = 0;
581  loopofs = 0;
582  polyofs = 0;
583 
584  /* Inverse transform for all selected meshes in this object,
585  * See #object_join_exec for detailed comment on why the safe version is used. */
586  invert_m4_m4_safe_ortho(imat, ob->obmat);
587 
588  /* Add back active mesh first.
589  * This allows to keep things similar as they were, as much as possible
590  * (i.e. data from active mesh will remain first ones in new result of the merge,
591  * in same order for CD layers, etc). See also T50084.
592  */
594  bmain,
595  scene,
596  ob,
597  ob,
598  imat,
599  &mvert,
600  &medge,
601  &mloop,
602  &mpoly,
603  &vdata,
604  &edata,
605  &ldata,
606  &pdata,
607  totvert,
608  totedge,
609  totloop,
610  totpoly,
611  key,
612  nkey,
613  matar,
614  matmap,
615  totcol,
616  &vertofs,
617  &edgeofs,
618  &loopofs,
619  &polyofs);
620 
621  CTX_DATA_BEGIN (C, Object *, ob_iter, selected_editable_objects) {
622  if (ob_iter == ob) {
623  continue;
624  }
625  /* only join if this is a mesh */
626  if (ob_iter->type == OB_MESH) {
628  bmain,
629  scene,
630  ob,
631  ob_iter,
632  imat,
633  &mvert,
634  &medge,
635  &mloop,
636  &mpoly,
637  &vdata,
638  &edata,
639  &ldata,
640  &pdata,
641  totvert,
642  totedge,
643  totloop,
644  totpoly,
645  key,
646  nkey,
647  matar,
648  matmap,
649  totcol,
650  &vertofs,
651  &edgeofs,
652  &loopofs,
653  &polyofs);
654 
655  /* free base, now that data is merged */
656  if (ob_iter != ob) {
657  ED_object_base_free_and_unlink(bmain, scene, ob_iter);
658  }
659  }
660  }
661  CTX_DATA_END;
662 
663  /* return to mesh we're merging to */
664  me = static_cast<Mesh *>(ob->data);
665 
666  CustomData_free(&me->vdata, me->totvert);
667  CustomData_free(&me->edata, me->totedge);
668  CustomData_free(&me->ldata, me->totloop);
669  CustomData_free(&me->pdata, me->totpoly);
670 
671  me->totvert = totvert;
672  me->totedge = totedge;
673  me->totloop = totloop;
674  me->totpoly = totpoly;
675 
676  me->vdata = vdata;
677  me->edata = edata;
678  me->ldata = ldata;
679  me->pdata = pdata;
680 
681  /* tessface data removed above, no need to update */
683 
684  /* Tag normals dirty because vertex positions could be changed from the original. */
686 
687  /* old material array */
688  for (a = 1; a <= ob->totcol; a++) {
689  ma = ob->mat[a - 1];
690  if (ma) {
691  id_us_min(&ma->id);
692  }
693  }
694  for (a = 1; a <= me->totcol; a++) {
695  ma = me->mat[a - 1];
696  if (ma) {
697  id_us_min(&ma->id);
698  }
699  }
700  MEM_SAFE_FREE(ob->mat);
701  MEM_SAFE_FREE(ob->matbits);
702  MEM_SAFE_FREE(me->mat);
703 
704  if (totcol) {
705  me->mat = matar;
706  ob->mat = static_cast<Material **>(MEM_callocN(sizeof(*ob->mat) * totcol, __func__));
707  ob->matbits = static_cast<char *>(MEM_callocN(sizeof(*ob->matbits) * totcol, __func__));
708  MEM_freeN(matmap);
709  }
710 
711  ob->totcol = me->totcol = totcol;
712 
713  /* other mesh users */
714  BKE_objects_materials_test_all(bmain, (ID *)me);
715 
716  /* Free temporary copy of destination shape-keys (if applicable). */
717  if (nkey) {
718  /* We can assume nobody is using that ID currently. */
719  BKE_id_free_ex(bmain, nkey, LIB_ID_FREE_NO_UI_USER, false);
720  }
721 
722  /* ensure newly inserted keys are time sorted */
723  if (key && (key->type != KEY_RELATIVE)) {
724  BKE_key_sort(key);
725  }
726 
727  /* Due to dependency cycle some other object might access old derived data. */
729 
730  DEG_relations_tag_update(bmain); /* removed objects, need to rebuild dag */
731 
733 
737 
738  return OPERATOR_FINISHED;
739 }
740 
741 /* -------------------------------------------------------------------- */
748 {
749  Main *bmain = CTX_data_main(C);
751  Object *ob_active = CTX_data_active_object(C);
753  Mesh *me = (Mesh *)ob_active->data;
754  Mesh *selme = nullptr;
755  Mesh *me_deformed = nullptr;
756  Key *key = me->key;
757  KeyBlock *kb;
758  bool ok = false, nonequal_verts = false;
759 
760  CTX_DATA_BEGIN (C, Object *, ob_iter, selected_editable_objects) {
761  if (ob_iter == ob_active) {
762  continue;
763  }
764 
765  if (ob_iter->type == OB_MESH) {
766  selme = (Mesh *)ob_iter->data;
767 
768  if (selme->totvert == me->totvert) {
769  ok = true;
770  }
771  else {
772  nonequal_verts = true;
773  }
774  }
775  }
776  CTX_DATA_END;
777 
778  if (!ok) {
779  if (nonequal_verts) {
780  BKE_report(op->reports, RPT_WARNING, "Selected meshes must have equal numbers of vertices");
781  }
782  else {
783  BKE_report(op->reports,
784  RPT_WARNING,
785  "No additional selected meshes with equal vertex count to join");
786  }
787  return OPERATOR_CANCELLED;
788  }
789 
790  if (key == nullptr) {
791  key = me->key = BKE_key_add(bmain, (ID *)me);
792  key->type = KEY_RELATIVE;
793 
794  /* first key added, so it was the basis. initialize it with the existing mesh */
795  kb = BKE_keyblock_add(key, nullptr);
796  BKE_keyblock_convert_from_mesh(me, key, kb);
797  }
798 
799  /* now ready to add new keys from selected meshes */
800  CTX_DATA_BEGIN (C, Object *, ob_iter, selected_editable_objects) {
801  if (ob_iter == ob_active) {
802  continue;
803  }
804 
805  if (ob_iter->type == OB_MESH) {
806  selme = (Mesh *)ob_iter->data;
807 
808  if (selme->totvert == me->totvert) {
809  Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
810  Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob_iter);
811 
812  me_deformed = mesh_get_eval_deform(depsgraph, scene_eval, ob_eval, &CD_MASK_BAREMESH);
813 
814  if (!me_deformed) {
815  continue;
816  }
817 
818  kb = BKE_keyblock_add(key, ob_iter->id.name + 2);
819 
820  BKE_mesh_runtime_eval_to_meshkey(me_deformed, me, kb);
821  }
822  }
823  }
824  CTX_DATA_END;
825 
828 
829  return OPERATOR_FINISHED;
830 }
831 
834 /* -------------------------------------------------------------------- */
838 static MirrTopoStore_t mesh_topo_store = {nullptr, -1, -1, false};
839 
841  Mesh *me_eval,
842  Mesh **r_me_mirror,
843  BMEditMesh **r_em_mirror)
844 {
845  Mesh *me_mirror = nullptr;
846  BMEditMesh *em_mirror = nullptr;
847 
848  Mesh *me = static_cast<Mesh *>(ob->data);
849  if (me_eval != nullptr) {
850  me_mirror = me_eval;
851  }
852  else if (me->edit_mesh != nullptr) {
853  em_mirror = me->edit_mesh;
854  }
855  else {
856  me_mirror = me;
857  }
858 
859  *r_me_mirror = me_mirror;
860  *r_em_mirror = em_mirror;
861 }
862 
864 {
865  Mesh *me_mirror;
866  BMEditMesh *em_mirror;
867  mesh_mirror_topo_table_get_meshes(ob, me_eval, &me_mirror, &em_mirror);
868 
869  ED_mesh_mirrtopo_init(em_mirror, me_mirror, &mesh_topo_store, false);
870 }
871 
873 {
874  /* TODO: store this in object/object-data (keep unused argument for now). */
876 }
877 
878 /* Returns true on success. */
879 static bool ed_mesh_mirror_topo_table_update(Object *ob, Mesh *me_eval)
880 {
881  Mesh *me_mirror;
882  BMEditMesh *em_mirror;
883  mesh_mirror_topo_table_get_meshes(ob, me_eval, &me_mirror, &em_mirror);
884 
885  if (ED_mesh_mirrtopo_recalc_check(em_mirror, me_mirror, &mesh_topo_store)) {
886  ED_mesh_mirror_topo_table_begin(ob, me_eval);
887  }
888  return true;
889 }
890 
893 static int mesh_get_x_mirror_vert_spatial(Object *ob, Mesh *me_eval, int index)
894 {
895  Mesh *me = static_cast<Mesh *>(ob->data);
896  MVert *mvert = me_eval ? me_eval->mvert : me->mvert;
897  float vec[3];
898 
899  mvert = &mvert[index];
900  vec[0] = -mvert->co[0];
901  vec[1] = mvert->co[1];
902  vec[2] = mvert->co[2];
903 
904  return ED_mesh_mirror_spatial_table_lookup(ob, nullptr, me_eval, vec);
905 }
906 
907 static int mesh_get_x_mirror_vert_topo(Object *ob, Mesh *mesh, int index)
908 {
910  return -1;
911  }
912 
913  return mesh_topo_store.index_lookup[index];
914 }
915 
916 int mesh_get_x_mirror_vert(Object *ob, Mesh *me_eval, int index, const bool use_topology)
917 {
918  if (use_topology) {
919  return mesh_get_x_mirror_vert_topo(ob, me_eval, index);
920  }
921  return mesh_get_x_mirror_vert_spatial(ob, me_eval, index);
922 }
923 
924 static BMVert *editbmesh_get_x_mirror_vert_spatial(Object *ob, BMEditMesh *em, const float co[3])
925 {
926  float vec[3];
927  int i;
928 
929  /* ignore nan verts */
930  if ((isfinite(co[0]) == false) || (isfinite(co[1]) == false) || (isfinite(co[2]) == false)) {
931  return nullptr;
932  }
933 
934  vec[0] = -co[0];
935  vec[1] = co[1];
936  vec[2] = co[2];
937 
938  i = ED_mesh_mirror_spatial_table_lookup(ob, em, nullptr, vec);
939  if (i != -1) {
940  return BM_vert_at_index(em->bm, i);
941  }
942  return nullptr;
943 }
944 
946 {
947  intptr_t poinval;
948  if (!ed_mesh_mirror_topo_table_update(ob, nullptr)) {
949  return nullptr;
950  }
951 
952  if (index == -1) {
953  BMIter iter;
954  BMVert *v;
955 
956  index = 0;
957  BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
958  if (v == eve) {
959  break;
960  }
961  index++;
962  }
963 
964  if (index == em->bm->totvert) {
965  return nullptr;
966  }
967  }
968 
969  poinval = mesh_topo_store.index_lookup[index];
970 
971  if (poinval != -1) {
972  return (BMVert *)(poinval);
973  }
974  return nullptr;
975 }
976 
978  Object *ob, BMEditMesh *em, BMVert *eve, const float co[3], int index, const bool use_topology)
979 {
980  if (use_topology) {
981  return editbmesh_get_x_mirror_vert_topo(ob, em, eve, index);
982  }
983  return editbmesh_get_x_mirror_vert_spatial(ob, em, co);
984 }
985 
986 int ED_mesh_mirror_get_vert(Object *ob, int index)
987 {
988  Mesh *me = static_cast<Mesh *>(ob->data);
989  BMEditMesh *em = me->edit_mesh;
990  bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0;
991  int index_mirr;
992 
993  if (em) {
994  BMVert *eve, *eve_mirr;
995  eve = BM_vert_at_index(em->bm, index);
996  eve_mirr = editbmesh_get_x_mirror_vert(ob, em, eve, eve->co, index, use_topology);
997  index_mirr = eve_mirr ? BM_elem_index_get(eve_mirr) : -1;
998  }
999  else {
1000  index_mirr = mesh_get_x_mirror_vert(ob, nullptr, index, use_topology);
1001  }
1002 
1003  return index_mirr;
1004 }
1005 
1006 #if 0
1007 
1008 static float *editmesh_get_mirror_uv(
1009  BMEditMesh *em, int axis, float *uv, float *mirrCent, float *face_cent)
1010 {
1011  float vec[2];
1012  float cent_vec[2];
1013  float cent[2];
1014 
1015  /* ignore nan verts */
1016  if (isnan(uv[0]) || !isfinite(uv[0]) || isnan(uv[1]) || !isfinite(uv[1])) {
1017  return nullptr;
1018  }
1019 
1020  if (axis) {
1021  vec[0] = uv[0];
1022  vec[1] = -((uv[1]) - mirrCent[1]) + mirrCent[1];
1023 
1024  cent_vec[0] = face_cent[0];
1025  cent_vec[1] = -((face_cent[1]) - mirrCent[1]) + mirrCent[1];
1026  }
1027  else {
1028  vec[0] = -((uv[0]) - mirrCent[0]) + mirrCent[0];
1029  vec[1] = uv[1];
1030 
1031  cent_vec[0] = -((face_cent[0]) - mirrCent[0]) + mirrCent[0];
1032  cent_vec[1] = face_cent[1];
1033  }
1034 
1035  /* TODO: Optimize. */
1036  {
1037  BMIter iter;
1038  BMFace *efa;
1039 
1040  BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1041  BM_face_uv_calc_center_median(efa, cd_loop_uv_offset, cent);
1042 
1043  if ((fabsf(cent[0] - cent_vec[0]) < 0.001f) && (fabsf(cent[1] - cent_vec[1]) < 0.001f)) {
1044  BMIter liter;
1045  BMLoop *l;
1046 
1047  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1049  if ((fabsf(luv->uv[0] - vec[0]) < 0.001f) && (fabsf(luv->uv[1] - vec[1]) < 0.001f)) {
1050  return luv->uv;
1051  }
1052  }
1053  }
1054  }
1055  }
1056 
1057  return nullptr;
1058 }
1059 
1060 #endif
1061 
1062 static uint mirror_facehash(const void *ptr)
1063 {
1064  const MFace *mf = static_cast<const MFace *>(ptr);
1065  uint v0, v1;
1066 
1067  if (mf->v4) {
1068  v0 = MIN4(mf->v1, mf->v2, mf->v3, mf->v4);
1069  v1 = MAX4(mf->v1, mf->v2, mf->v3, mf->v4);
1070  }
1071  else {
1072  v0 = MIN3(mf->v1, mf->v2, mf->v3);
1073  v1 = MAX3(mf->v1, mf->v2, mf->v3);
1074  }
1075 
1076  return ((v0 * 39) ^ (v1 * 31));
1077 }
1078 
1080 {
1081  if (b->v4) {
1082  if (a->v1 == b->v1 && a->v2 == b->v2 && a->v3 == b->v3 && a->v4 == b->v4) {
1083  return 0;
1084  }
1085  if (a->v4 == b->v1 && a->v1 == b->v2 && a->v2 == b->v3 && a->v3 == b->v4) {
1086  return 1;
1087  }
1088  if (a->v3 == b->v1 && a->v4 == b->v2 && a->v1 == b->v3 && a->v2 == b->v4) {
1089  return 2;
1090  }
1091  if (a->v2 == b->v1 && a->v3 == b->v2 && a->v4 == b->v3 && a->v1 == b->v4) {
1092  return 3;
1093  }
1094  }
1095  else {
1096  if (a->v1 == b->v1 && a->v2 == b->v2 && a->v3 == b->v3) {
1097  return 0;
1098  }
1099  if (a->v3 == b->v1 && a->v1 == b->v2 && a->v2 == b->v3) {
1100  return 1;
1101  }
1102  if (a->v2 == b->v1 && a->v3 == b->v2 && a->v1 == b->v3) {
1103  return 2;
1104  }
1105  }
1106 
1107  return -1;
1108 }
1109 
1110 static bool mirror_facecmp(const void *a, const void *b)
1111 {
1112  return (mirror_facerotation((MFace *)a, (MFace *)b) == -1);
1113 }
1114 
1116 {
1117  Mesh *me = static_cast<Mesh *>(ob->data);
1118  MVert *mv, *mvert;
1119  MFace mirrormf, *mf, *hashmf, *mface;
1120  GHash *fhash;
1121  int *mirrorverts, *mirrorfaces;
1122 
1123  BLI_assert(em == nullptr); /* Does not work otherwise, currently... */
1124 
1125  const bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0;
1126  const int totvert = me_eval ? me_eval->totvert : me->totvert;
1127  const int totface = me_eval ? me_eval->totface : me->totface;
1128  int a;
1129 
1130  mirrorverts = static_cast<int *>(MEM_callocN(sizeof(int) * totvert, "MirrorVerts"));
1131  mirrorfaces = static_cast<int *>(MEM_callocN(sizeof(int[2]) * totface, "MirrorFaces"));
1132 
1133  mvert = me_eval ? me_eval->mvert : me->mvert;
1134  mface = me_eval ? me_eval->mface : me->mface;
1135 
1136  ED_mesh_mirror_spatial_table_begin(ob, em, me_eval);
1137 
1138  for (a = 0, mv = mvert; a < totvert; a++, mv++) {
1139  mirrorverts[a] = mesh_get_x_mirror_vert(ob, me_eval, a, use_topology);
1140  }
1141 
1143 
1144  fhash = BLI_ghash_new_ex(mirror_facehash, mirror_facecmp, "mirror_facehash gh", me->totface);
1145  for (a = 0, mf = mface; a < totface; a++, mf++) {
1146  BLI_ghash_insert(fhash, mf, mf);
1147  }
1148 
1149  for (a = 0, mf = mface; a < totface; a++, mf++) {
1150  mirrormf.v1 = mirrorverts[mf->v3];
1151  mirrormf.v2 = mirrorverts[mf->v2];
1152  mirrormf.v3 = mirrorverts[mf->v1];
1153  mirrormf.v4 = (mf->v4) ? mirrorverts[mf->v4] : 0;
1154 
1155  /* make sure v4 is not 0 if a quad */
1156  if (mf->v4 && mirrormf.v4 == 0) {
1157  SWAP(uint, mirrormf.v1, mirrormf.v3);
1158  SWAP(uint, mirrormf.v2, mirrormf.v4);
1159  }
1160 
1161  hashmf = static_cast<MFace *>(BLI_ghash_lookup(fhash, &mirrormf));
1162  if (hashmf) {
1163  mirrorfaces[a * 2] = hashmf - mface;
1164  mirrorfaces[a * 2 + 1] = mirror_facerotation(&mirrormf, hashmf);
1165  }
1166  else {
1167  mirrorfaces[a * 2] = -1;
1168  }
1169  }
1170 
1171  BLI_ghash_free(fhash, nullptr, nullptr);
1172  MEM_freeN(mirrorverts);
1173 
1174  return mirrorfaces;
1175 }
1176 
1177 /* Selection (vertex and face). */
1178 
1179 bool ED_mesh_pick_face(bContext *C, Object *ob, const int mval[2], uint dist_px, uint *r_index)
1180 {
1181  ViewContext vc;
1182  Mesh *me = static_cast<Mesh *>(ob->data);
1183 
1184  BLI_assert(me && GS(me->id.name) == ID_ME);
1185 
1186  if (!me || me->totpoly == 0) {
1187  return false;
1188  }
1189 
1193 
1194  if (dist_px) {
1195  /* Sample rect to increase chances of selecting, so that when clicking
1196  * on an edge in the back-buffer, we can still select a face. */
1198  vc.depsgraph, vc.region, vc.v3d, mval, 1, me->totpoly + 1, &dist_px);
1199  }
1200  else {
1201  /* sample only on the exact position */
1202  *r_index = DRW_select_buffer_sample_point(vc.depsgraph, vc.region, vc.v3d, mval);
1203  }
1204 
1205  if ((*r_index) == 0 || (*r_index) > (uint)me->totpoly) {
1206  return false;
1207  }
1208 
1209  (*r_index)--;
1210 
1211  return true;
1212 }
1213 
1215  /* context */
1216  ARegion *region,
1217  const float mval[2],
1218  /* mesh data (evaluated) */
1219  const MPoly *mp,
1220  const MVert *mvert,
1221  const MLoop *mloop,
1222  /* return values */
1223  float *r_len_best,
1224  int *r_v_idx_best)
1225 {
1226  const MLoop *ml;
1227  int j = mp->totloop;
1228  for (ml = &mloop[mp->loopstart]; j--; ml++) {
1229  float sco[2];
1230  const int v_idx = ml->v;
1231  const float *co = mvert[v_idx].co;
1233  const float len_test = len_manhattan_v2v2(mval, sco);
1234  if (len_test < *r_len_best) {
1235  *r_len_best = len_test;
1236  *r_v_idx_best = v_idx;
1237  }
1238  }
1239  }
1240 }
1242  bContext *C, Object *ob, const int mval[2], uint dist_px, uint *r_index)
1243 {
1245  uint poly_index;
1246  Mesh *me = static_cast<Mesh *>(ob->data);
1247 
1248  BLI_assert(me && GS(me->id.name) == ID_ME);
1249 
1250  if (ED_mesh_pick_face(C, ob, mval, dist_px, &poly_index)) {
1251  Scene *scene_eval = DEG_get_evaluated_scene(depsgraph);
1252  Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob);
1253  ARegion *region = CTX_wm_region(C);
1254 
1255  /* derived mesh to find deformed locations */
1256  Mesh *me_eval = mesh_get_eval_final(
1257  depsgraph, scene_eval, ob_eval, &CD_MASK_BAREMESH_ORIGINDEX);
1258 
1259  int v_idx_best = ORIGINDEX_NONE;
1260 
1261  /* find the vert closest to 'mval' */
1262  const float mval_f[2] = {(float)mval[0], (float)mval[1]};
1263  float len_best = FLT_MAX;
1264 
1265  MPoly *me_eval_mpoly;
1266  MLoop *me_eval_mloop;
1267  MVert *me_eval_mvert;
1268  uint me_eval_mpoly_len;
1269 
1270  me_eval_mpoly = me_eval->mpoly;
1271  me_eval_mloop = me_eval->mloop;
1272  me_eval_mvert = me_eval->mvert;
1273 
1274  me_eval_mpoly_len = me_eval->totpoly;
1275 
1276  const int *index_mp_to_orig = (const int *)CustomData_get_layer(&me_eval->pdata, CD_ORIGINDEX);
1277 
1278  /* tag all verts using this face */
1279  if (index_mp_to_orig) {
1280  uint i;
1281 
1282  for (i = 0; i < me_eval_mpoly_len; i++) {
1283  if (index_mp_to_orig[i] == poly_index) {
1285  mval_f,
1286  &me_eval_mpoly[i],
1287  me_eval_mvert,
1288  me_eval_mloop,
1289  &len_best,
1290  &v_idx_best);
1291  }
1292  }
1293  }
1294  else {
1295  if (poly_index < me_eval_mpoly_len) {
1297  mval_f,
1298  &me_eval_mpoly[poly_index],
1299  me_eval_mvert,
1300  me_eval_mloop,
1301  &len_best,
1302  &v_idx_best);
1303  }
1304  }
1305 
1306  /* map 'dm -> me' r_index if possible */
1307  if (v_idx_best != ORIGINDEX_NONE) {
1308  const int *index_mv_to_orig = (const int *)CustomData_get_layer(&me_eval->vdata,
1309  CD_ORIGINDEX);
1310  if (index_mv_to_orig) {
1311  v_idx_best = index_mv_to_orig[v_idx_best];
1312  }
1313  }
1314 
1315  if ((v_idx_best != ORIGINDEX_NONE) && (v_idx_best < me->totvert)) {
1316  *r_index = v_idx_best;
1317  return true;
1318  }
1319  }
1320 
1321  return false;
1322 }
1323 
1331  const MVert *mvert;
1332  const float *mval_f; /* [2] */
1334 
1335  /* runtime */
1336  float len_best;
1338 };
1339 
1340 static void ed_mesh_pick_vert__mapFunc(void *userData,
1341  int index,
1342  const float co[3],
1343  const float UNUSED(no[3]))
1344 {
1345  VertPickData *data = static_cast<VertPickData *>(userData);
1346  if ((data->mvert[index].flag & ME_HIDE) == 0) {
1347  float sco[2];
1348 
1350  V3D_PROJ_RET_OK) {
1351  const float len = len_manhattan_v2v2(data->mval_f, sco);
1352  if (len < data->len_best) {
1353  data->len_best = len;
1354  data->v_idx_best = index;
1355  }
1356  }
1357  }
1358 }
1360  bContext *C, Object *ob, const int mval[2], uint dist_px, bool use_zbuf, uint *r_index)
1361 {
1362  ViewContext vc;
1363  Mesh *me = static_cast<Mesh *>(ob->data);
1364 
1365  BLI_assert(me && GS(me->id.name) == ID_ME);
1366 
1367  if (!me || me->totvert == 0) {
1368  return false;
1369  }
1370 
1374 
1375  if (use_zbuf) {
1376  if (dist_px > 0) {
1377  /* Sample rectangle to increase chances of selecting, so that when clicking
1378  * on an face in the back-buffer, we can still select a vert. */
1380  vc.depsgraph, vc.region, vc.v3d, mval, 1, me->totvert + 1, &dist_px);
1381  }
1382  else {
1383  /* sample only on the exact position */
1384  *r_index = DRW_select_buffer_sample_point(vc.depsgraph, vc.region, vc.v3d, mval);
1385  }
1386 
1387  if ((*r_index) == 0 || (*r_index) > (uint)me->totvert) {
1388  return false;
1389  }
1390 
1391  (*r_index)--;
1392  }
1393  else {
1394  Scene *scene_eval = DEG_get_evaluated_scene(vc.depsgraph);
1395  Object *ob_eval = DEG_get_evaluated_object(vc.depsgraph, ob);
1396 
1397  /* derived mesh to find deformed locations */
1398  Mesh *me_eval = mesh_get_eval_final(vc.depsgraph, scene_eval, ob_eval, &CD_MASK_BAREMESH);
1399  ARegion *region = vc.region;
1400  RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
1401 
1402  /* find the vert closest to 'mval' */
1403  const float mval_f[2] = {(float)mval[0], (float)mval[1]};
1404 
1405  VertPickData data = {nullptr};
1406 
1407  ED_view3d_init_mats_rv3d(ob, rv3d);
1408 
1409  if (me_eval == nullptr) {
1410  return false;
1411  }
1412 
1413  /* setup data */
1414  data.mvert = me->mvert;
1415  data.region = region;
1416  data.mval_f = mval_f;
1417  data.len_best = FLT_MAX;
1418  data.v_idx_best = -1;
1419 
1421 
1422  if (data.v_idx_best == -1) {
1423  return false;
1424  }
1425 
1426  *r_index = data.v_idx_best;
1427  }
1428 
1429  return true;
1430 }
1431 
1433 {
1434  if (ob->mode & OB_MODE_EDIT && ob->type == OB_MESH) {
1435  Mesh *me = static_cast<Mesh *>(ob->data);
1437  BMesh *bm = me->edit_mesh->bm;
1438  const int cd_dvert_offset = CustomData_get_offset(&bm->vdata, CD_MDEFORMVERT);
1439 
1440  if (cd_dvert_offset != -1) {
1442 
1443  if (eve) {
1444  if (r_eve) {
1445  *r_eve = eve;
1446  }
1447  return static_cast<MDeformVert *>(BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset));
1448  }
1449  }
1450  }
1451  }
1452 
1453  if (r_eve) {
1454  *r_eve = nullptr;
1455  }
1456  return nullptr;
1457 }
1458 
1460 {
1461  Mesh *me = static_cast<Mesh *>(ob->data);
1462  int index = BKE_mesh_mselect_active_get(me, ME_VSEL);
1463  if (r_index) {
1464  *r_index = index;
1465  }
1466  if (index == -1 || me->dvert == nullptr) {
1467  return nullptr;
1468  }
1469  return me->dvert + index;
1470 }
1471 
1473 {
1474  if (ob->type == OB_MESH) {
1475  if (ob->mode & OB_MODE_EDIT) {
1476  return ED_mesh_active_dvert_get_em(ob, nullptr);
1477  }
1478  return ED_mesh_active_dvert_get_ob(ob, nullptr);
1479  }
1480  return nullptr;
1481 }
1482 
1484  const uint objects_len,
1485  int totelem[3],
1486  int totelem_sel[3])
1487 {
1488  if (totelem) {
1489  totelem[0] = 0;
1490  totelem[1] = 0;
1491  totelem[2] = 0;
1492  }
1493  if (totelem_sel) {
1494  totelem_sel[0] = 0;
1495  totelem_sel[1] = 0;
1496  totelem_sel[2] = 0;
1497  }
1498 
1499  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1500  Object *obedit = objects[ob_index];
1501  BMEditMesh *em = BKE_editmesh_from_object(obedit);
1502  BMesh *bm = em->bm;
1503  if (totelem) {
1504  totelem[0] += bm->totvert;
1505  totelem[1] += bm->totedge;
1506  totelem[2] += bm->totface;
1507  }
1508  if (totelem_sel) {
1509  totelem_sel[0] += bm->totvertsel;
1510  totelem_sel[1] += bm->totedgesel;
1511  totelem_sel[2] += bm->totfacesel;
1512  }
1513  }
1514 }
1515 
1516 void EDBM_mesh_elem_index_ensure_multi(Object **objects, const uint objects_len, const char htype)
1517 {
1518  int elem_offset[4] = {0, 0, 0, 0};
1519  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1520  Object *obedit = objects[ob_index];
1521  BMEditMesh *em = BKE_editmesh_from_object(obedit);
1522  BMesh *bm = em->bm;
1524  }
1525 }
typedef float(TangentPoint)[2]
struct Scene * CTX_data_scene(const bContext *C)
Definition: context.c:1090
#define CTX_DATA_BEGIN(C, Type, instance, member)
Definition: BKE_context.h:269
struct Depsgraph * CTX_data_ensure_evaluated_depsgraph(const bContext *C)
Definition: context.c:1528
struct Object * CTX_data_active_object(const bContext *C)
Definition: context.c:1353
struct ARegion * CTX_wm_region(const bContext *C)
Definition: context.c:749
struct Main * CTX_data_main(const bContext *C)
Definition: context.c:1074
#define CTX_DATA_END
Definition: BKE_context.h:278
CustomData interface, see also DNA_customdata_types.h.
bool CustomData_merge(const struct CustomData *source, struct CustomData *dest, eCustomDataMask mask, eCDAllocType alloctype, int totelem)
void CustomData_copy_data_named(const struct CustomData *source, struct CustomData *dest, int source_index, int dest_index, int count)
void CustomData_free(struct CustomData *data, int totelem)
Definition: customdata.cc:2373
const CustomData_MeshMasks CD_MASK_BAREMESH_ORIGINDEX
Definition: customdata.cc:2058
@ CD_CALLOC
@ CD_DEFAULT
const CustomData_MeshMasks CD_MASK_BAREMESH
Definition: customdata.cc:2051
#define ORIGINDEX_NONE
void * CustomData_get_layer(const struct CustomData *data, int type)
void * CustomData_bmesh_get(const struct CustomData *data, void *block, int type)
void * CustomData_add_layer(struct CustomData *data, int type, eCDAllocType alloctype, void *layer, int totelem)
Definition: customdata.cc:2776
void * CustomData_get(const struct CustomData *data, int index, int type)
int CustomData_get_offset(const struct CustomData *data, int type)
const CustomData_MeshMasks CD_MASK_MESH
Definition: customdata.cc:2065
void CustomData_reset(struct CustomData *data)
Definition: customdata.cc:2367
support for deformation groups and hooks.
struct bDeformGroup * BKE_object_defgroup_find_name(const struct Object *ob, const char *name)
BMEditMesh * BKE_editmesh_from_object(struct Object *ob)
Return the BMEditMesh for a given object.
Definition: editmesh.c:58
struct KeyBlock * BKE_keyblock_find_name(struct Key *key, const char name[])
Definition: key.c:1930
void BKE_keyblock_copy_settings(struct KeyBlock *kb_dst, const struct KeyBlock *kb_src)
copy shape-key attributes, but not key data or name/UID.
void BKE_keyblock_convert_from_mesh(const struct Mesh *me, const struct Key *key, struct KeyBlock *kb)
void BKE_key_sort(struct Key *key)
Definition: key.c:304
struct KeyBlock * BKE_keyblock_add(struct Key *key, const char *name)
Definition: key.c:1814
struct Key * BKE_key_add(struct Main *bmain, struct ID *id)
Definition: key.c:252
struct ID * BKE_id_copy(struct Main *bmain, const struct ID *id)
void id_us_min(struct ID *id)
Definition: lib_id.c:313
@ LIB_ID_FREE_NO_UI_USER
Definition: BKE_lib_id.h:256
void id_us_plus(struct ID *id)
Definition: lib_id.c:305
void BKE_id_free_ex(struct Main *bmain, void *idv, int flag, bool use_flag_from_idtag)
Definition: lib_id_delete.c:82
General operations, lookup, etc. for materials.
struct Material * BKE_object_material_get(struct Object *ob, short act)
Definition: material.c:687
void BKE_objects_materials_test_all(struct Main *bmain, struct ID *id)
Definition: material.c:886
void BKE_mesh_tessface_clear(struct Mesh *mesh)
Definition: mesh.cc:1654
struct Mesh * BKE_mesh_from_object(struct Object *ob)
Definition: mesh.cc:1365
int BKE_mesh_mselect_active_get(struct Mesh *me, int type)
Definition: mesh.cc:1772
void BKE_mesh_update_customdata_pointers(struct Mesh *me, bool do_ensure_tess_cd)
Definition: mesh.cc:874
void BKE_mesh_clear_derived_normals(struct Mesh *mesh)
void BKE_mesh_normals_tag_dirty(struct Mesh *mesh)
Definition: mesh_normals.cc:95
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
void BKE_mesh_runtime_eval_to_meshkey(struct Mesh *me_deformed, struct Mesh *me, struct KeyBlock *kb)
Definition: DerivedMesh.cc:390
struct Mesh * mesh_get_eval_deform(struct Depsgraph *depsgraph, const struct Scene *scene, struct Object *ob, const struct CustomData_MeshMasks *dataMask)
void BKE_mesh_runtime_clear_geometry(struct Mesh *mesh)
struct Mesh * mesh_get_eval_final(struct Depsgraph *depsgraph, const struct Scene *scene, struct Object *ob, const struct CustomData_MeshMasks *dataMask)
void multiresModifier_prepare_join(struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, struct Object *to_ob)
Definition: multires.c:1431
struct MultiresModifierData * get_multires_modifier(struct Scene *scene, struct Object *ob, bool use_first)
Definition: multires.c:317
General operations, lookup, etc. for blender objects.
void BKE_object_apply_mat4_ex(struct Object *ob, const float mat[4][4], struct Object *parent, const float parentinv[4][4], bool use_compat)
Definition: object.cc:3532
void BKE_object_free_derived_caches(struct Object *ob)
Definition: object.cc:1774
Functions for dealing with objects and deform verts, used by painting and tools.
int * BKE_object_defgroup_index_map_create(struct Object *ob_src, struct Object *ob_dst, int *r_map_len)
void BKE_object_defgroup_index_map_apply(struct MDeformVert *dvert, int dvert_len, const int *map, int map_len)
Functions for dealing with object face-maps.
int * BKE_object_facemap_index_map_create(struct Object *ob_src, struct Object *ob_dst, int *r_map_len)
void BKE_object_facemap_index_map_apply(int *fmap, int fmap_len, const int *map, int map_len)
struct bFaceMap * BKE_object_facemap_find_name(struct Object *ob, const char *name)
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition: report.c:83
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define BLI_INLINE
void * BLI_ghash_lookup(const GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:734
GHash * BLI_ghash_new_ex(GHashHashFP hashfp, GHashCmpFP cmpfp, const char *info, unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:681
void BLI_ghash_insert(GHash *gh, void *key, void *val)
Definition: BLI_ghash.c:710
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition: BLI_ghash.c:863
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
Definition: BLI_listbase.h:269
#define LISTBASE_FOREACH(type, var, list)
Definition: BLI_listbase.h:336
#define LISTBASE_FOREACH_INDEX(type, var, list, index_var)
Definition: BLI_listbase.h:344
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:80
int BLI_findindex(const struct ListBase *listbase, const void *vlink) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
MINLINE int max_ii(int a, int b)
void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4])
Definition: math_matrix.c:259
void invert_m4_m4_safe_ortho(float Ainv[4][4], const float A[4][4])
Definition: math_matrix.c:3188
void mul_m4_v3(const float M[4][4], float r[3])
Definition: math_matrix.c:729
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE float len_manhattan_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT
unsigned int uint
Definition: BLI_sys_types.h:67
#define MIN4(a, b, c, d)
#define MAX3(a, b, c)
#define MIN3(a, b, c)
#define SWAP(type, a, b)
#define UNUSED(x)
#define ELEM(...)
#define MAX4(a, b, c, d)
#define LIKELY(x)
struct Depsgraph Depsgraph
Definition: DEG_depsgraph.h:35
void DEG_id_tag_update(struct ID *id, int flag)
void DEG_relations_tag_update(struct Main *bmain)
struct Object * DEG_get_evaluated_object(const struct Depsgraph *depsgraph, struct Object *object)
struct Scene * DEG_get_evaluated_scene(const struct Depsgraph *graph)
@ ID_RECALC_TRANSFORM
Definition: DNA_ID.h:771
@ ID_RECALC_SELECT
Definition: DNA_ID.h:818
@ ID_RECALC_GEOMETRY
Definition: DNA_ID.h:791
@ ID_ME
Definition: DNA_ID_enums.h:48
@ CD_FACEMAP
@ CD_MDEFORMVERT
@ CD_ORIGINDEX
@ CD_SCULPT_FACE_SETS
@ CD_MEDGE
@ CD_MVERT
@ CD_MLOOPUV
@ KEY_RELATIVE
#define MAXMAT
@ ME_EDIT_MIRROR_TOPO
#define MESH_MAX_VERTS
@ ME_VSEL
@ ME_HIDE
@ OB_MODE_EDIT
Object is a sort of wrapper for general info.
@ OB_MESH
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
uint DRW_select_buffer_find_nearest_to_point(struct Depsgraph *depsgraph, struct ARegion *region, struct View3D *v3d, const int center[2], uint id_min, uint id_max, uint *dist)
uint DRW_select_buffer_sample_point(struct Depsgraph *depsgraph, struct ARegion *region, struct View3D *v3d, const int center[2])
bool ED_mesh_mirrtopo_recalc_check(struct BMEditMesh *em, struct Mesh *me, MirrTopoStore_t *mesh_topo_store)
void ED_mesh_mirrtopo_free(MirrTopoStore_t *mesh_topo_store)
void ED_mesh_mirror_spatial_table_begin(struct Object *ob, struct BMEditMesh *em, struct Mesh *me_eval)
void ED_mesh_mirror_spatial_table_end(struct Object *ob)
int ED_mesh_mirror_spatial_table_lookup(struct Object *ob, struct BMEditMesh *em, struct Mesh *me_eval, const float co[3])
void ED_mesh_mirrtopo_init(struct BMEditMesh *em, struct Mesh *me, MirrTopoStore_t *mesh_topo_store, bool skip_em_vert_array_init)
bool ED_object_multires_update_totlevels_cb(struct Object *ob, void *totlevel_v)
bool ED_object_iter_other(struct Main *bmain, struct Object *orig_ob, bool include_orig, bool(*callback)(struct Object *ob, void *callback_data), void *callback_data)
void ED_object_base_free_and_unlink(struct Main *bmain, struct Scene *scene, struct Object *ob)
Definition: object_add.cc:2190
@ V3D_PROJ_TEST_NOP
Definition: ED_view3d.h:234
void ED_view3d_viewcontext_init(struct bContext *C, struct ViewContext *vc, struct Depsgraph *depsgraph)
@ V3D_PROJ_RET_OK
Definition: ED_view3d.h:217
void ED_view3d_select_id_validate(struct ViewContext *vc)
Definition: view3d_draw.c:2190
#define V3D_PROJ_TEST_CLIP_DEFAULT
Definition: ED_view3d.h:264
eV3DProjStatus ED_view3d_project_float_object(const struct ARegion *region, const float co[3], float r_co[2], eV3DProjTest flag)
void ED_view3d_init_mats_rv3d(const struct Object *ob, struct RegionView3D *rv3d)
Definition: space_view3d.c:166
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble v1
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
#define C
Definition: RandGen.cpp:25
#define ND_OB_ACTIVE
Definition: WM_types.h:388
#define NC_SCENE
Definition: WM_types.h:328
#define ND_LAYER_CONTENT
Definition: WM_types.h:402
#define BM_ELEM_CD_GET_VOID_P(ele, offset)
Definition: bmesh_class.h:541
#define BM_elem_index_get(ele)
Definition: bmesh_inline.h:110
#define BM_ITER_ELEM(ele, iter, data, itype)
#define BM_ITER_MESH(ele, iter, bm, itype)
@ BM_VERTS_OF_MESH
@ BM_FACES_OF_MESH
@ BM_LOOPS_OF_FACE
ATTR_WARN_UNUSED_RESULT BMesh * bm
BMVert * BM_mesh_active_vert_get(BMesh *bm)
void BM_mesh_elem_index_ensure_ex(BMesh *bm, const char htype, int elem_offset[4])
Definition: bmesh_mesh.cc:332
BLI_INLINE BMVert * BM_vert_at_index(BMesh *bm, const int index)
Definition: bmesh_mesh.h:103
ATTR_WARN_UNUSED_RESULT const BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMVert * v
void BM_face_uv_calc_center_median(const BMFace *f, const int cd_loop_uv_offset, float r_cent[2])
Scene scene
const Depsgraph * depsgraph
static int elem_offset(const SDNA *sdna, const char *type, const char *name, const SDNA_Struct *old)
Definition: dna_genfile.c:954
int len
Definition: draw_manager.c:108
#define GS(x)
Definition: iris.c:225
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:33
static bool mirror_facecmp(const void *a, const void *b)
Definition: meshtools.cc:1110
void ED_mesh_mirror_topo_table_begin(Object *ob, Mesh *me_eval)
Definition: meshtools.cc:863
static void ed_mesh_pick_face_vert__mpoly_find(ARegion *region, const float mval[2], const MPoly *mp, const MVert *mvert, const MLoop *mloop, float *r_len_best, int *r_v_idx_best)
Definition: meshtools.cc:1214
int * mesh_get_x_mirror_faces(Object *ob, BMEditMesh *em, Mesh *me_eval)
Definition: meshtools.cc:1115
static uint mirror_facehash(const void *ptr)
Definition: meshtools.cc:1062
static BMVert * editbmesh_get_x_mirror_vert_topo(Object *ob, BMEditMesh *em, BMVert *eve, int index)
Definition: meshtools.cc:945
static bool ed_mesh_mirror_topo_table_update(Object *ob, Mesh *me_eval)
Definition: meshtools.cc:879
static void join_mesh_single(Depsgraph *depsgraph, Main *bmain, Scene *scene, Object *ob_dst, Object *ob_src, const float imat[4][4], MVert **mvert_pp, MEdge **medge_pp, MLoop **mloop_pp, MPoly **mpoly_pp, CustomData *vdata, CustomData *edata, CustomData *ldata, CustomData *pdata, int totvert, int totedge, int totloop, int totpoly, Key *key, Key *nkey, Material **matar, int *matmap, int totcol, int *vertofs, int *edgeofs, int *loopofs, int *polyofs)
Definition: meshtools.cc:62
int ED_mesh_shapes_join_objects_exec(bContext *C, wmOperator *op)
Definition: meshtools.cc:747
int mesh_get_x_mirror_vert(Object *ob, Mesh *me_eval, int index, const bool use_topology)
Definition: meshtools.cc:916
static int mesh_get_x_mirror_vert_spatial(Object *ob, Mesh *me_eval, int index)
Definition: meshtools.cc:893
int ED_mesh_mirror_get_vert(Object *ob, int index)
Definition: meshtools.cc:986
int ED_mesh_join_objects_exec(bContext *C, wmOperator *op)
Definition: meshtools.cc:314
MDeformVert * ED_mesh_active_dvert_get_only(Object *ob)
Definition: meshtools.cc:1472
bool ED_mesh_pick_face_vert(bContext *C, Object *ob, const int mval[2], uint dist_px, uint *r_index)
Definition: meshtools.cc:1241
void EDBM_mesh_elem_index_ensure_multi(Object **objects, const uint objects_len, const char htype)
Definition: meshtools.cc:1516
MDeformVert * ED_mesh_active_dvert_get_em(Object *ob, BMVert **r_eve)
Definition: meshtools.cc:1432
static MirrTopoStore_t mesh_topo_store
Definition: meshtools.cc:838
bool ED_mesh_pick_face(bContext *C, Object *ob, const int mval[2], uint dist_px, uint *r_index)
Definition: meshtools.cc:1179
static void ed_mesh_pick_vert__mapFunc(void *userData, int index, const float co[3], const float UNUSED(no[3]))
Definition: meshtools.cc:1340
void ED_mesh_mirror_topo_table_end(Object *UNUSED(ob))
Definition: meshtools.cc:872
static int mirror_facerotation(MFace *a, MFace *b)
Definition: meshtools.cc:1079
BMVert * editbmesh_get_x_mirror_vert(Object *ob, BMEditMesh *em, BMVert *eve, const float co[3], int index, const bool use_topology)
Definition: meshtools.cc:977
BLI_INLINE void mesh_mirror_topo_table_get_meshes(Object *ob, Mesh *me_eval, Mesh **r_me_mirror, BMEditMesh **r_em_mirror)
Definition: meshtools.cc:840
static BMVert * editbmesh_get_x_mirror_vert_spatial(Object *ob, BMEditMesh *em, const float co[3])
Definition: meshtools.cc:924
MDeformVert * ED_mesh_active_dvert_get_ob(Object *ob, int *r_index)
Definition: meshtools.cc:1459
bool ED_mesh_pick_vert(bContext *C, Object *ob, const int mval[2], uint dist_px, bool use_zbuf, uint *r_index)
Definition: meshtools.cc:1359
void EDBM_mesh_stats_multi(Object **objects, const uint objects_len, int totelem[3], int totelem_sel[3])
Definition: meshtools.cc:1483
static void mesh_join_offset_face_sets_ID(const Mesh *mesh, int *face_set_offset)
Definition: meshtools.cc:286
static int mesh_get_x_mirror_vert_topo(Object *ob, Mesh *mesh, int index)
Definition: meshtools.cc:907
#define fabsf(x)
Definition: metal/compat.h:219
bool isfinite(uchar)
Definition: scene/image.cpp:31
static unsigned a[3]
Definition: RandGen.cpp:78
INLINE Rall1d< T, V, S > cos(const Rall1d< T, V, S > &arg)
Definition: rall1d.h:319
T abs(const T &a)
bool isnan(double i)
Definition: numeric.h:451
static const pxr::TfToken b("b", pxr::TfToken::Immortal)
_W64 int intptr_t
Definition: stdint.h:118
void * regiondata
struct BMesh * bm
Definition: BKE_editmesh.h:40
void * data
Definition: bmesh_class.h:51
BMHeader head
Definition: bmesh_class.h:145
float co[3]
Definition: bmesh_class.h:87
int totvert
Definition: bmesh_class.h:297
int totfacesel
Definition: bmesh_class.h:298
CustomData vdata
Definition: bmesh_class.h:337
int totedge
Definition: bmesh_class.h:297
int totvertsel
Definition: bmesh_class.h:298
int totedgesel
Definition: bmesh_class.h:298
CustomData ldata
Definition: bmesh_class.h:337
int totface
Definition: bmesh_class.h:297
Definition: DNA_ID.h:368
char name[66]
Definition: DNA_ID.h:378
short relative
Definition: DNA_key_types.h:41
void * data
Definition: DNA_key_types.h:50
int totkey
Definition: DNA_key_types.h:91
ID id
Definition: DNA_key_types.h:63
char type
Definition: DNA_key_types.h:94
ListBase block
Definition: DNA_key_types.h:84
void * first
Definition: DNA_listBase.h:31
unsigned int v1
unsigned int v2
unsigned int v2
unsigned int v1
unsigned int v4
unsigned int v3
unsigned int e
unsigned int v
short mat_nr
float co[3]
Definition: BKE_main.h:121
struct BMEditMesh * edit_mesh
CustomData vdata
struct MVert * mvert
struct Material ** mat
struct MDeformVert * dvert
int totedge
ListBase vertex_group_names
char cd_flag
char editflag
int totvert
struct MLoop * mloop
int totface
CustomData pdata
int totpoly
short totcol
int vertex_group_active_index
CustomData edata
int totloop
struct Key * key
struct MFace * mface
struct MPoly * mpoly
CustomData ldata
intptr_t * index_lookup
Definition: ED_mesh.h:432
ustring name
Definition: graph/node.h:174
struct Material ** mat
char * matbits
unsigned short actfmap
float parentinv[4][4]
float obmat[4][4]
struct Object * parent
void * data
ListBase fmaps
const float * mval_f
Definition: meshtools.cc:1332
const MVert * mvert
Definition: meshtools.cc:1331
ARegion * region
Definition: meshtools.cc:1333
float len_best
Definition: meshtools.cc:1336
struct Depsgraph * depsgraph
Definition: ED_view3d.h:64
struct ARegion * region
Definition: ED_view3d.h:69
struct View3D * v3d
Definition: ED_view3d.h:70
struct ReportList * reports
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
PointerRNA * ptr
Definition: wm_files.c:3480