Blender V4.5
meshtools.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2004 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
11
12#include <algorithm>
13
14#include "MEM_guardedalloc.h"
15
16#include "BLI_listbase.h"
17#include "BLI_math_matrix.h"
18#include "BLI_vector.hh"
19#include "BLI_virtual_array.hh"
20
21#include "DNA_key_types.h"
22#include "DNA_material_types.h"
23#include "DNA_mesh_types.h"
24#include "DNA_meshdata_types.h"
25#include "DNA_modifier_types.h"
26#include "DNA_object_types.h"
27#include "DNA_scene_types.h"
28#include "DNA_screen_types.h"
29#include "DNA_view3d_types.h"
30
31#include "BKE_attribute.hh"
32#include "BKE_context.hh"
33#include "BKE_customdata.hh"
34#include "BKE_deform.hh"
35#include "BKE_editmesh.hh"
36#include "BKE_key.hh"
37#include "BKE_layer.hh"
38#include "BKE_lib_id.hh"
39#include "BKE_material.hh"
40#include "BKE_mesh.hh"
41#include "BKE_mesh_iterators.hh"
42#include "BKE_mesh_runtime.hh"
43#include "BKE_multires.hh"
44#include "BKE_object.hh"
45#include "BKE_object_deform.h"
46#include "BKE_report.hh"
47
48#include "DEG_depsgraph.hh"
51
52#include "DRW_select_buffer.hh"
53
54#include "ED_mesh.hh"
55#include "ED_object.hh"
56#include "ED_view3d.hh"
57
58#include "WM_api.hh"
59#include "WM_types.hh"
60
61using blender::float3;
62using blender::int2;
64using blender::Span;
65
66/* * ********************** no editmode!!! *********** */
67
68/*********************** JOIN ***************************/
69
70/* join selected meshes into the active mesh, context sensitive
71 * return 0 if no join is made (error) and 1 if the join is done */
72
73static void join_mesh_single(Depsgraph *depsgraph,
74 Main *bmain,
75 Scene *scene,
76 Object *ob_dst,
77 Object *ob_src,
78 const float imat[4][4],
79 float3 **vert_positions_pp,
80 blender::int2 **medge_pp,
81 int **corner_verts_pp,
82 int **corner_edges_pp,
83 int *all_face_offsets,
84 CustomData *vert_data,
85 CustomData *edge_data,
86 CustomData *ldata,
87 CustomData *face_data,
88 int totvert,
89 int totedge,
90 int totloop,
91 int faces_num,
92 Key *key,
93 Key *nkey,
95 int *vertofs,
96 int *edgeofs,
97 int *loopofs,
98 int *polyofs)
99{
100 int a;
101
102 Mesh *mesh = static_cast<Mesh *>(ob_src->data);
103 float3 *vert_positions = *vert_positions_pp;
104 blender::int2 *edge = *medge_pp;
105 int *corner_verts = *corner_verts_pp;
106 int *corner_edges = *corner_edges_pp;
107
108 if (mesh->verts_num) {
109 /* standard data */
111 &mesh->vert_data, vert_data, CD_MASK_MESH.vmask, CD_SET_DEFAULT, totvert);
112 CustomData_copy_data_named(&mesh->vert_data, vert_data, 0, *vertofs, mesh->verts_num);
113
114 /* vertex groups */
116 vert_data, *vertofs, CD_MDEFORMVERT, totvert);
117 const MDeformVert *dvert_src = (const MDeformVert *)CustomData_get_layer(&mesh->vert_data,
119
120 /* Remap to correct new vgroup indices, if needed. */
121 if (dvert_src) {
122 BLI_assert(dvert != nullptr);
123
124 /* Build src to merged mapping of vgroup indices. */
125 int *vgroup_index_map;
126 int vgroup_index_map_len;
127 vgroup_index_map = BKE_object_defgroup_index_map_create(
128 ob_src, ob_dst, &vgroup_index_map_len);
130 dvert, mesh->verts_num, vgroup_index_map, vgroup_index_map_len);
131 if (vgroup_index_map != nullptr) {
132 MEM_freeN(vgroup_index_map);
133 }
134 }
135
136 /* if this is the object we're merging into, no need to do anything */
137 if (ob_src != ob_dst) {
138 float cmat[4][4];
139
140 /* Watch this: switch matrix multiplication order really goes wrong. */
141 mul_m4_m4m4(cmat, imat, ob_src->object_to_world().ptr());
142
143 /* transform vertex coordinates into new space */
144 for (a = 0; a < mesh->verts_num; a++) {
145 mul_m4_v3(cmat, vert_positions[a]);
146 }
147
148 /* For each shape-key in destination mesh:
149 * - if there's a matching one, copy it across
150 * (will need to transform vertices into new space...).
151 * - otherwise, just copy its own coordinates of mesh
152 * (no need to transform vertex coordinates into new space).
153 */
154 if (key) {
155 /* if this mesh has any shape-keys, check first, otherwise just copy coordinates */
156 LISTBASE_FOREACH (KeyBlock *, kb, &key->block) {
157 /* get pointer to where to write data for this mesh in shape-key's data array */
158 float(*cos)[3] = ((float(*)[3])kb->data) + *vertofs;
159
160 /* Check if this mesh has such a shape-key. */
161 KeyBlock *okb = mesh->key ? BKE_keyblock_find_name(mesh->key, kb->name) : nullptr;
162 if (okb) {
163 /* copy this mesh's shape-key to the destination shape-key
164 * (need to transform first) */
165 float(*ocos)[3] = static_cast<float(*)[3]>(okb->data);
166 for (a = 0; a < mesh->verts_num; a++, cos++, ocos++) {
167 copy_v3_v3(*cos, *ocos);
168 mul_m4_v3(cmat, *cos);
169 }
170 }
171 else {
172 /* Copy this mesh's vertex coordinates to the destination shape-key. */
173 for (a = 0; a < mesh->verts_num; a++, cos++) {
174 copy_v3_v3(*cos, vert_positions[a]);
175 }
176 }
177 }
178 }
179 }
180 else {
181 /* for each shape-key in destination mesh:
182 * - if it was an 'original', copy the appropriate data from nkey
183 * - otherwise, copy across plain coordinates (no need to transform coordinates)
184 */
185 if (key) {
186 LISTBASE_FOREACH (KeyBlock *, kb, &key->block) {
187 /* get pointer to where to write data for this mesh in shape-key's data array */
188 float(*cos)[3] = ((float(*)[3])kb->data) + *vertofs;
189
190 /* Check if this was one of the original shape-keys. */
191 KeyBlock *okb = nkey ? BKE_keyblock_find_name(nkey, kb->name) : nullptr;
192 if (okb) {
193 /* copy this mesh's shape-key to the destination shape-key */
194 float(*ocos)[3] = static_cast<float(*)[3]>(okb->data);
195 for (a = 0; a < mesh->verts_num; a++, cos++, ocos++) {
196 copy_v3_v3(*cos, *ocos);
197 }
198 }
199 else {
200 /* Copy base-coordinates to the destination shape-key. */
201 for (a = 0; a < mesh->verts_num; a++, cos++) {
202 copy_v3_v3(*cos, vert_positions[a]);
203 }
204 }
205 }
206 }
207 }
208 }
209
210 if (mesh->edges_num) {
212 &mesh->edge_data, edge_data, CD_MASK_MESH.emask, CD_SET_DEFAULT, totedge);
213 CustomData_copy_data_named(&mesh->edge_data, edge_data, 0, *edgeofs, mesh->edges_num);
214
215 for (a = 0; a < mesh->edges_num; a++, edge++) {
216 (*edge) += *vertofs;
217 }
218 }
219
220 if (mesh->corners_num) {
221 if (ob_src != ob_dst) {
223
224 multiresModifier_prepare_join(depsgraph, scene, ob_src, ob_dst);
225
226 if ((mmd = get_multires_modifier(scene, ob_src, true))) {
228 bmain, ob_src, true, blender::ed::object::multires_update_totlevels, &mmd->totlvl);
229 }
230 }
231
233 &mesh->corner_data, ldata, CD_MASK_MESH.lmask, CD_SET_DEFAULT, totloop);
234 CustomData_copy_data_named(&mesh->corner_data, ldata, 0, *loopofs, mesh->corners_num);
235
236 for (a = 0; a < mesh->corners_num; a++) {
237 corner_verts[a] += *vertofs;
238 corner_edges[a] += *edgeofs;
239 }
240 }
241
242 /* Make remapping for material indices. Assume at least one slot,
243 * that will be null if there are no actual slots. */
244 const int totcol = std::max(ob_src->totcol, 1);
245 blender::Vector<int> matmap(totcol);
246 if (mesh->faces_num) {
247 for (a = 1; a <= totcol; a++) {
248 Material *ma = (a <= ob_src->totcol) ? BKE_object_material_get(ob_src, a) : nullptr;
249
250 /* Try to reuse existing slot. */
251 int b = 0;
252 for (; b < matar.size(); b++) {
253 if (ma == matar[b]) {
254 matmap[a - 1] = b;
255 break;
256 }
257 }
258
259 if (b == matar.size()) {
260 if (matar.size() == MAXMAT) {
261 /* Reached max limit of materials, use first slot. */
262 matmap[a - 1] = 0;
263 }
264 else {
265 /* Add new slot. */
266 matmap[a - 1] = matar.size();
267 matar.append(ma);
268 if (ma) {
269 id_us_plus(&ma->id);
270 }
271 }
272 }
273 }
274
276 &mesh->face_data, face_data, CD_MASK_MESH.pmask, CD_SET_DEFAULT, faces_num);
277 CustomData_copy_data_named(&mesh->face_data, face_data, 0, *polyofs, mesh->faces_num);
278
279 /* Apply matmap. In case we don't have material indices yet, create them if more than one
280 * material is the result of joining. */
281 int *material_indices = static_cast<int *>(CustomData_get_layer_named_for_write(
282 face_data, CD_PROP_INT32, "material_index", faces_num));
283 if (!material_indices && matar.size() > 1) {
284 material_indices = (int *)CustomData_add_layer_named(
285 face_data, CD_PROP_INT32, CD_SET_DEFAULT, faces_num, "material_index");
286 }
287 if (material_indices) {
288 for (a = 0; a < mesh->faces_num; a++) {
289 /* Clamp invalid slots, matching #BKE_object_material_get_p. */
290 const int mat_index = std::clamp(material_indices[a + *polyofs], 0, totcol - 1);
291 material_indices[a + *polyofs] = matmap[mat_index];
292 }
293 }
294
295 const Span<int> src_face_offsets = mesh->face_offsets();
296 int *face_offsets = all_face_offsets + *polyofs;
297 for (const int i : blender::IndexRange(mesh->faces_num)) {
298 face_offsets[i] = src_face_offsets[i] + *loopofs;
299 }
300 }
301
302 /* these are used for relinking (cannot be set earlier, or else reattaching goes wrong) */
303 *vertofs += mesh->verts_num;
304 *vert_positions_pp += mesh->verts_num;
305 *edgeofs += mesh->edges_num;
306 *medge_pp += mesh->edges_num;
307 *loopofs += mesh->corners_num;
308 *corner_verts_pp += mesh->corners_num;
309 *corner_edges_pp += mesh->corners_num;
310 *polyofs += mesh->faces_num;
311}
312
313/* Face Sets IDs are a sparse sequence, so this function offsets all the IDs by face_set_offset and
314 * updates face_set_offset with the maximum ID value. This way, when used in multiple meshes, all
315 * of them will have different IDs for their Face Sets. */
316static void mesh_join_offset_face_sets_ID(Mesh *mesh, int *face_set_offset)
317{
318 using namespace blender;
319 bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
320 bke::SpanAttributeWriter<int> face_sets = attributes.lookup_for_write_span<int>(
321 ".sculpt_face_set");
322 if (!face_sets) {
323 return;
324 }
325
326 int max_face_set = 0;
327 for (const int i : face_sets.span.index_range()) {
328 /* As face sets encode the visibility in the integer sign, the offset needs to be added or
329 * subtracted depending on the initial sign of the integer to get the new ID. */
330 if (face_sets.span[i] <= *face_set_offset) {
331 face_sets.span[i] += *face_set_offset;
332 }
333 max_face_set = max_ii(max_face_set, face_sets.span[i]);
334 }
335 *face_set_offset = max_face_set;
336 face_sets.finish();
337}
338
340{
341 Main *bmain = CTX_data_main(C);
342 Scene *scene = CTX_data_scene(C);
344 Material *ma;
345 Mesh *mesh;
346 blender::int2 *edge = nullptr;
347 Key *key, *nkey = nullptr;
348 float imat[4][4];
349 int a, totedge = 0, totvert = 0;
350 int totloop = 0, faces_num = 0, vertofs;
351 int i, haskey = 0, edgeofs, loopofs, polyofs;
352 bool ok = false, join_parent = false;
353 CustomData vert_data, edge_data, ldata, face_data;
354
355 if (ob->mode & OB_MODE_EDIT) {
356 BKE_report(op->reports, RPT_WARNING, "Cannot join while in edit mode");
357 return OPERATOR_CANCELLED;
358 }
359
360 /* ob is the object we are adding geometry to */
361 if (!ob || ob->type != OB_MESH) {
362 BKE_report(op->reports, RPT_WARNING, "Active object is not a mesh");
363 return OPERATOR_CANCELLED;
364 }
365
367
368 /* count & check */
369 CTX_DATA_BEGIN (C, Object *, ob_iter, selected_editable_objects) {
370 if (ob_iter->type == OB_MESH) {
371 mesh = static_cast<Mesh *>(ob_iter->data);
372
373 totvert += mesh->verts_num;
374 totedge += mesh->edges_num;
375 totloop += mesh->corners_num;
376 faces_num += mesh->faces_num;
377
378 if (ob_iter == ob) {
379 ok = true;
380 }
381
382 if ((ob->parent != nullptr) && (ob_iter == ob->parent)) {
383 join_parent = true;
384 }
385
386 /* Check for shape-keys. */
387 if (mesh->key) {
388 haskey++;
389 }
390 }
391 }
393
394 /* Apply parent transform if the active object's parent was joined to it.
395 * NOTE: This doesn't apply recursive parenting. */
396 if (join_parent) {
397 ob->parent = nullptr;
398 BKE_object_apply_mat4_ex(ob, ob->object_to_world().ptr(), ob->parent, ob->parentinv, false);
399 }
400
401 /* that way the active object is always selected */
402 if (ok == false) {
403 BKE_report(op->reports, RPT_WARNING, "Active object is not a selected mesh");
404 return OPERATOR_CANCELLED;
405 }
406
407 /* Only join meshes if there are verts to join,
408 * there aren't too many, and we only had one mesh selected. */
409 mesh = (Mesh *)ob->data;
410 key = mesh->key;
411
412 if (ELEM(totvert, 0, mesh->verts_num)) {
413 BKE_report(op->reports, RPT_WARNING, "No mesh data to join");
414 return OPERATOR_CANCELLED;
415 }
416
417 if (totvert > MESH_MAX_VERTS) {
420 "Joining results in %d vertices, limit is %ld",
421 totvert,
423 return OPERATOR_CANCELLED;
424 }
425
426 /* Active object materials in new main array, is nicer start! */
428 for (a = 0; a < ob->totcol; a++) {
429 matar.append(BKE_object_material_get(ob, a + 1));
430 id_us_plus((ID *)matar[a]);
431 /* increase id->us : will be lowered later */
432 }
433
434 /* - If destination mesh had shape-keys, move them somewhere safe, and set up placeholders
435 * with arrays that are large enough to hold shape-key data for all meshes.
436 * - If destination mesh didn't have shape-keys, but we encountered some in the meshes we're
437 * joining, set up a new key-block and assign to the mesh.
438 */
439 if (key) {
440 /* make a duplicate copy that will only be used here... (must remember to free it!) */
441 nkey = (Key *)BKE_id_copy(bmain, &key->id);
442
443 /* for all keys in old block, clear data-arrays */
444 LISTBASE_FOREACH (KeyBlock *, kb, &key->block) {
445 if (kb->data) {
446 MEM_freeN(kb->data);
447 }
448 kb->data = MEM_callocN(sizeof(float[3]) * totvert, "join_shapekey");
449 kb->totelem = totvert;
450 }
451 }
452 else if (haskey) {
453 /* add a new key-block and add to the mesh */
454 key = mesh->key = BKE_key_add(bmain, (ID *)mesh);
455 key->type = KEY_RELATIVE;
456 }
457
458 /* Update face_set_id_offset with the face set data in the active object first. This way the Face
459 * Sets IDs in the active object are not the ones that are modified. */
460 Mesh *mesh_active = BKE_mesh_from_object(ob);
461 int face_set_id_offset = 0;
462 mesh_join_offset_face_sets_ID(mesh_active, &face_set_id_offset);
463
464 /* Copy materials, vertex-groups, face sets & face-maps across objects. */
465 CTX_DATA_BEGIN (C, Object *, ob_iter, selected_editable_objects) {
466 /* only act if a mesh, and not the one we're joining to */
467 if ((ob != ob_iter) && (ob_iter->type == OB_MESH)) {
468 mesh = static_cast<Mesh *>(ob_iter->data);
469
470 /* Join this object's vertex groups to the base one's */
472 /* See if this group exists in the object (if it doesn't, add it to the end) */
473 if (!BKE_object_defgroup_find_name(ob, dg->name)) {
475 memcpy(odg, dg, sizeof(bDeformGroup));
476 BLI_addtail(&mesh_active->vertex_group_names, odg);
477 }
478 }
479 if (!BLI_listbase_is_empty(&mesh_active->vertex_group_names) &&
480 mesh->vertex_group_active_index == 0)
481 {
483 }
484
485 mesh_join_offset_face_sets_ID(mesh, &face_set_id_offset);
486
487 if (mesh->verts_num) {
488 /* If this mesh has shape-keys,
489 * check if destination mesh already has matching entries too. */
490 if (mesh->key && key) {
491 /* for remapping KeyBlock.relative */
492 int *index_map = MEM_malloc_arrayN<int>(mesh->key->totkey, __func__);
493 KeyBlock **kb_map = MEM_malloc_arrayN<KeyBlock *>(mesh->key->totkey, __func__);
494
495 LISTBASE_FOREACH_INDEX (KeyBlock *, kb, &mesh->key->block, i) {
497
498 KeyBlock *kbn = BKE_keyblock_find_name(key, kb->name);
499 /* if key doesn't exist in destination mesh, add it */
500 if (kbn) {
501 index_map[i] = BLI_findindex(&key->block, kbn);
502 }
503 else {
504 index_map[i] = key->totkey;
505
506 kbn = BKE_keyblock_add(key, kb->name);
507
509
510 /* adjust settings to fit (allocate a new data-array) */
511 kbn->data = MEM_callocN(sizeof(float[3]) * totvert, "joined_shapekey");
512 kbn->totelem = totvert;
513 }
514
515 kb_map[i] = kbn;
516 }
517
518 /* remap relative index values */
519 LISTBASE_FOREACH_INDEX (KeyBlock *, kb, &mesh->key->block, i) {
520 /* sanity check, should always be true */
521 if (LIKELY(kb->relative < mesh->key->totkey)) {
522 kb_map[i]->relative = index_map[kb->relative];
523 }
524 }
525
526 MEM_freeN(index_map);
527 MEM_freeN(kb_map);
528 }
529 }
530 }
531 }
533
534 /* setup new data for destination mesh */
535 CustomData_reset(&vert_data);
536 CustomData_reset(&edge_data);
537 CustomData_reset(&ldata);
538 CustomData_reset(&face_data);
539
540 float3 *vert_positions = (float3 *)CustomData_add_layer_named(
541 &vert_data, CD_PROP_FLOAT3, CD_SET_DEFAULT, totvert, "position");
543 &edge_data, CD_PROP_INT32_2D, CD_CONSTRUCT, totedge, ".edge_verts");
544 int *corner_verts = (int *)CustomData_add_layer_named(
545 &ldata, CD_PROP_INT32, CD_CONSTRUCT, totloop, ".corner_vert");
546 int *corner_edges = (int *)CustomData_add_layer_named(
547 &ldata, CD_PROP_INT32, CD_CONSTRUCT, totloop, ".corner_edge");
548 int *face_offsets = MEM_malloc_arrayN<int>(faces_num + 1, __func__);
549 face_offsets[faces_num] = totloop;
550
551 vertofs = 0;
552 edgeofs = 0;
553 loopofs = 0;
554 polyofs = 0;
555
556 /* Inverse transform for all selected meshes in this object,
557 * See #object_join_exec for detailed comment on why the safe version is used. */
558 invert_m4_m4_safe_ortho(imat, ob->object_to_world().ptr());
559
560 /* Add back active mesh first.
561 * This allows to keep things similar as they were, as much as possible
562 * (i.e. data from active mesh will remain first ones in new result of the merge,
563 * in same order for CD layers, etc). See also #50084.
564 */
566 bmain,
567 scene,
568 ob,
569 ob,
570 imat,
571 &vert_positions,
572 &edge,
573 &corner_verts,
574 &corner_edges,
575 face_offsets,
576 &vert_data,
577 &edge_data,
578 &ldata,
579 &face_data,
580 totvert,
581 totedge,
582 totloop,
583 faces_num,
584 key,
585 nkey,
586 matar,
587 &vertofs,
588 &edgeofs,
589 &loopofs,
590 &polyofs);
591
592 CTX_DATA_BEGIN (C, Object *, ob_iter, selected_editable_objects) {
593 if (ob_iter == ob) {
594 continue;
595 }
596 /* only join if this is a mesh */
597 if (ob_iter->type == OB_MESH) {
599 bmain,
600 scene,
601 ob,
602 ob_iter,
603 imat,
604 &vert_positions,
605 &edge,
606 &corner_verts,
607 &corner_edges,
608 face_offsets,
609 &vert_data,
610 &edge_data,
611 &ldata,
612 &face_data,
613 totvert,
614 totedge,
615 totloop,
616 faces_num,
617 key,
618 nkey,
619 matar,
620 &vertofs,
621 &edgeofs,
622 &loopofs,
623 &polyofs);
624
625 /* free base, now that data is merged */
626 if (ob_iter != ob) {
627 blender::ed::object::base_free_and_unlink(bmain, scene, ob_iter);
628 }
629 }
630 }
632
633 /* return to mesh we're merging to */
634 mesh = static_cast<Mesh *>(ob->data);
635
637
638 if (faces_num) {
639 mesh->face_offset_indices = face_offsets;
640 mesh->runtime->face_offsets_sharing_info = blender::implicit_sharing::info_for_mem_free(
641 face_offsets);
642 }
643
644 mesh->verts_num = totvert;
645 mesh->edges_num = totedge;
646 mesh->corners_num = totloop;
647 mesh->faces_num = faces_num;
648
649 mesh->vert_data = vert_data;
650 mesh->edge_data = edge_data;
651 mesh->corner_data = ldata;
652 mesh->face_data = face_data;
653
654 /* old material array */
655 for (a = 1; a <= ob->totcol; a++) {
656 ma = ob->mat[a - 1];
657 if (ma) {
658 id_us_min(&ma->id);
659 }
660 }
661 for (a = 1; a <= mesh->totcol; a++) {
662 ma = mesh->mat[a - 1];
663 if (ma) {
664 id_us_min(&ma->id);
665 }
666 }
667 MEM_SAFE_FREE(ob->mat);
669 MEM_SAFE_FREE(mesh->mat);
670
671 /* If the object had no slots, don't add an empty one. */
672 if (ob->totcol == 0 && matar.size() == 1 && matar[0] == nullptr) {
673 matar.clear();
674 }
675
676 const int totcol = matar.size();
677 if (totcol) {
678 mesh->mat = MEM_calloc_arrayN<Material *>(totcol, __func__);
679 std::copy_n(matar.data(), totcol, mesh->mat);
680 ob->mat = MEM_calloc_arrayN<Material *>(totcol, __func__);
681 ob->matbits = MEM_calloc_arrayN<char>(totcol, __func__);
682 }
683
684 ob->totcol = mesh->totcol = totcol;
685
686 /* other mesh users */
688
689 /* Free temporary copy of destination shape-keys (if applicable). */
690 if (nkey) {
691 /* We can assume nobody is using that ID currently. */
692 BKE_id_free_ex(bmain, nkey, LIB_ID_FREE_NO_UI_USER, false);
693 }
694
695 /* ensure newly inserted keys are time sorted */
696 if (key && (key->type != KEY_RELATIVE)) {
697 BKE_key_sort(key);
698 }
699
700 /* Due to dependency cycle some other object might access old derived data. */
702
703 DEG_relations_tag_update(bmain); /* removed objects, need to rebuild dag */
704
706
710
711 return OPERATOR_FINISHED;
712}
713
714/* -------------------------------------------------------------------- */
719
721 const bool ensure_keys_exist,
723{
724 using namespace blender;
725 Main *bmain = CTX_data_main(C);
726 Object &active_object = *CTX_data_active_object(C);
728 Mesh &active_mesh = *static_cast<Mesh *>(active_object.data);
729
730 struct ObjectInfo {
731 StringRefNull name;
732 const Mesh &mesh;
733 };
734
735 auto topology_count_matches = [](const Mesh &a, const Mesh &b) {
736 return a.verts_num == b.verts_num;
737 };
738
739 bool found_object = false;
740 bool found_non_equal_count = false;
741 Vector<ObjectInfo> compatible_objects;
742 CTX_DATA_BEGIN (C, Object *, ob_iter, selected_editable_objects) {
743 if (ob_iter == &active_object) {
744 continue;
745 }
746 if (ob_iter->type != OB_MESH) {
747 continue;
748 }
749 const Object *object_eval = DEG_get_evaluated(&depsgraph, ob_iter);
750 if (!object_eval) {
751 continue;
752 }
753 found_object = true;
754 if (const Mesh *mesh = BKE_object_get_evaluated_mesh(object_eval)) {
755 if (topology_count_matches(*mesh, active_mesh)) {
756 compatible_objects.append({BKE_id_name(ob_iter->id), *mesh});
757 continue;
758 }
759 }
760 /* Fall back to the original mesh. */
761 const Mesh &mesh_orig = *static_cast<const Mesh *>(ob_iter->data);
762 if (topology_count_matches(mesh_orig, active_mesh)) {
763 compatible_objects.append({BKE_id_name(ob_iter->id), mesh_orig});
764 continue;
765 }
766 found_non_equal_count = true;
767 }
769
770 if (!found_object) {
771 BKE_report(reports, RPT_WARNING, "No source mesh objects selected");
772 return OPERATOR_CANCELLED;
773 }
774
775 if (found_non_equal_count) {
776 BKE_report(reports, RPT_WARNING, "Selected meshes must have equal numbers of vertices");
777 return OPERATOR_CANCELLED;
778 }
779
780 if (compatible_objects.is_empty()) {
782 reports, RPT_WARNING, "No additional selected meshes with equal vertex count to join");
783 return OPERATOR_CANCELLED;
784 }
785
786 if (!active_mesh.key) {
787 /* Initialize basis shape key with existing mesh. */
788 active_mesh.key = BKE_key_add(bmain, &active_mesh.id);
789 active_mesh.key->type = KEY_RELATIVE;
791 &active_mesh, active_mesh.key, BKE_keyblock_add(active_mesh.key, nullptr));
792 }
793
794 int keys_changed = 0;
795 bool any_keys_added = false;
796 for (const ObjectInfo &info : compatible_objects) {
797 if (ensure_keys_exist) {
798 KeyBlock *kb = BKE_keyblock_add(active_mesh.key, info.name.c_str());
799 BKE_keyblock_convert_from_mesh(&info.mesh, active_mesh.key, kb);
800 any_keys_added = true;
801 }
802 else if (KeyBlock *kb = BKE_keyblock_find_name(active_mesh.key, info.name.c_str())) {
803 keys_changed++;
804 BKE_keyblock_update_from_mesh(&info.mesh, kb);
805 }
806 }
807
808 if (!ensure_keys_exist) {
809 if (keys_changed == 0) {
810 BKE_report(reports, RPT_ERROR, "No name matches between selected objects and shape keys");
811 return OPERATOR_CANCELLED;
812 }
813 BKE_reportf(reports, RPT_INFO, "Updated %d shape key(s)", keys_changed);
814 }
815
817 WM_main_add_notifier(NC_GEOM | ND_DATA, &active_mesh.id);
818
819 if (any_keys_added && bmain) {
820 /* Adding a new shape key should trigger a rebuild of relationships. */
822 }
823
824 return OPERATOR_FINISHED;
825}
826
828
829/* -------------------------------------------------------------------- */
832
833static MirrTopoStore_t mesh_topo_store = {nullptr, -1, -1, false};
834
836 Mesh *mesh_eval,
837 Mesh **r_mesh_mirror,
838 BMEditMesh **r_em_mirror)
839{
840 Mesh *mesh_mirror = nullptr;
841 BMEditMesh *em_mirror = nullptr;
842
843 Mesh *mesh = static_cast<Mesh *>(ob->data);
844 if (mesh_eval != nullptr) {
845 mesh_mirror = mesh_eval;
846 }
847 else if (BMEditMesh *em = mesh->runtime->edit_mesh.get()) {
848 em_mirror = em;
849 }
850 else {
851 mesh_mirror = mesh;
852 }
853
854 *r_mesh_mirror = mesh_mirror;
855 *r_em_mirror = em_mirror;
856}
857
859{
860 Mesh *mesh_mirror;
861 BMEditMesh *em_mirror;
862 mesh_mirror_topo_table_get_meshes(ob, mesh_eval, &mesh_mirror, &em_mirror);
863
864 ED_mesh_mirrtopo_init(em_mirror, mesh_mirror, &mesh_topo_store, false);
865}
866
868{
869 /* TODO: store this in object/object-data (keep unused argument for now). */
871}
872
873/* Returns true on success. */
874static bool ed_mesh_mirror_topo_table_update(Object *ob, Mesh *mesh_eval)
875{
876 Mesh *mesh_mirror;
877 BMEditMesh *em_mirror;
878 mesh_mirror_topo_table_get_meshes(ob, mesh_eval, &mesh_mirror, &em_mirror);
879
880 if (ED_mesh_mirrtopo_recalc_check(em_mirror, mesh_mirror, &mesh_topo_store)) {
881 ED_mesh_mirror_topo_table_begin(ob, mesh_eval);
882 }
883 return true;
884}
885
887
888static int mesh_get_x_mirror_vert_spatial(Object *ob, Mesh *mesh_eval, int index)
889{
890 Mesh *mesh = static_cast<Mesh *>(ob->data);
891 const Span<float3> positions = mesh_eval ? mesh_eval->vert_positions() : mesh->vert_positions();
892
893 float vec[3];
894
895 vec[0] = -positions[index][0];
896 vec[1] = positions[index][1];
897 vec[2] = positions[index][2];
898
899 return ED_mesh_mirror_spatial_table_lookup(ob, nullptr, mesh_eval, vec);
900}
901
902static int mesh_get_x_mirror_vert_topo(Object *ob, Mesh *mesh, int index)
903{
904 if (!ed_mesh_mirror_topo_table_update(ob, mesh)) {
905 return -1;
906 }
907
908 return mesh_topo_store.index_lookup[index];
909}
910
911int mesh_get_x_mirror_vert(Object *ob, Mesh *mesh_eval, int index, const bool use_topology)
912{
913 if (use_topology) {
914 return mesh_get_x_mirror_vert_topo(ob, mesh_eval, index);
915 }
916 return mesh_get_x_mirror_vert_spatial(ob, mesh_eval, index);
917}
918
920{
921 float vec[3];
922 int i;
923
924 /* ignore nan verts */
925 if ((isfinite(co[0]) == false) || (isfinite(co[1]) == false) || (isfinite(co[2]) == false)) {
926 return nullptr;
927 }
928
929 vec[0] = -co[0];
930 vec[1] = co[1];
931 vec[2] = co[2];
932
933 i = ED_mesh_mirror_spatial_table_lookup(ob, em, nullptr, vec);
934 if (i != -1) {
935 return BM_vert_at_index(em->bm, i);
936 }
937 return nullptr;
938}
939
941{
942 intptr_t poinval;
943 if (!ed_mesh_mirror_topo_table_update(ob, nullptr)) {
944 return nullptr;
945 }
946
947 if (index == -1) {
948 BMIter iter;
949 BMVert *v;
950
951 index = 0;
952 BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
953 if (v == eve) {
954 break;
955 }
956 index++;
957 }
958
959 if (index == em->bm->totvert) {
960 return nullptr;
961 }
962 }
963
964 poinval = mesh_topo_store.index_lookup[index];
965
966 if (poinval != -1) {
967 return (BMVert *)(poinval);
968 }
969 return nullptr;
970}
971
973 Object *ob, BMEditMesh *em, BMVert *eve, const float co[3], int index, const bool use_topology)
974{
975 if (use_topology) {
976 return editbmesh_get_x_mirror_vert_topo(ob, em, eve, index);
977 }
978 return editbmesh_get_x_mirror_vert_spatial(ob, em, co);
979}
980
982{
983 Mesh *mesh = static_cast<Mesh *>(ob->data);
984 bool use_topology = (mesh->editflag & ME_EDIT_MIRROR_TOPO) != 0;
985 int index_mirr;
986
987 if (BMEditMesh *em = mesh->runtime->edit_mesh.get()) {
988 BMVert *eve, *eve_mirr;
989 eve = BM_vert_at_index(em->bm, index);
990 eve_mirr = editbmesh_get_x_mirror_vert(ob, em, eve, eve->co, index, use_topology);
991 index_mirr = eve_mirr ? BM_elem_index_get(eve_mirr) : -1;
992 }
993 else {
994 index_mirr = mesh_get_x_mirror_vert(ob, nullptr, index, use_topology);
995 }
996
997 return index_mirr;
998}
999
1000#if 0
1001
1002static float *editmesh_get_mirror_uv(
1003 BMEditMesh *em, int axis, float *uv, float *mirrCent, float *face_cent)
1004{
1005 float vec[2];
1006 float cent_vec[2];
1007 float cent[2];
1008
1009 /* ignore nan verts */
1010 if (isnan(uv[0]) || !isfinite(uv[0]) || isnan(uv[1]) || !isfinite(uv[1])) {
1011 return nullptr;
1012 }
1013
1014 if (axis) {
1015 vec[0] = uv[0];
1016 vec[1] = -((uv[1]) - mirrCent[1]) + mirrCent[1];
1017
1018 cent_vec[0] = face_cent[0];
1019 cent_vec[1] = -((face_cent[1]) - mirrCent[1]) + mirrCent[1];
1020 }
1021 else {
1022 vec[0] = -((uv[0]) - mirrCent[0]) + mirrCent[0];
1023 vec[1] = uv[1];
1024
1025 cent_vec[0] = -((face_cent[0]) - mirrCent[0]) + mirrCent[0];
1026 cent_vec[1] = face_cent[1];
1027 }
1028
1029 /* TODO: Optimize. */
1030 {
1031 BMIter iter;
1032 BMFace *efa;
1033
1034 BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
1035 BM_face_uv_calc_center_median(efa, cd_loop_uv_offset, cent);
1036
1037 if ((fabsf(cent[0] - cent_vec[0]) < 0.001f) && (fabsf(cent[1] - cent_vec[1]) < 0.001f)) {
1038 BMIter liter;
1039 BMLoop *l;
1040
1041 BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
1042 float *luv2 = BM_ELEM_CD_GET_FLOAT_P(l, cd_loop_uv_offset);
1043 if ((fabsf(luv[0] - vec[0]) < 0.001f) && (fabsf(luv[1] - vec[1]) < 0.001f)) {
1044 return luv;
1045 }
1046 }
1047 }
1048 }
1049 }
1050
1051 return nullptr;
1052}
1053
1054#endif
1055
1056static uint mirror_facehash(const void *ptr)
1057{
1058 const MFace *mf = static_cast<const MFace *>(ptr);
1059 uint v0, v1;
1060
1061 if (mf->v4) {
1062 v0 = std::min({mf->v1, mf->v2, mf->v3, mf->v4});
1063 v1 = std::max({mf->v1, mf->v2, mf->v3, mf->v4});
1064 }
1065 else {
1066 v0 = std::min({mf->v1, mf->v2, mf->v3});
1067 v1 = std::min({mf->v1, mf->v2, mf->v3});
1068 }
1069
1070 return ((v0 * 39) ^ (v1 * 31));
1071}
1072
1073static int mirror_facerotation(const MFace *a, const MFace *b)
1074{
1075 if (b->v4) {
1076 if (a->v1 == b->v1 && a->v2 == b->v2 && a->v3 == b->v3 && a->v4 == b->v4) {
1077 return 0;
1078 }
1079 if (a->v4 == b->v1 && a->v1 == b->v2 && a->v2 == b->v3 && a->v3 == b->v4) {
1080 return 1;
1081 }
1082 if (a->v3 == b->v1 && a->v4 == b->v2 && a->v1 == b->v3 && a->v2 == b->v4) {
1083 return 2;
1084 }
1085 if (a->v2 == b->v1 && a->v3 == b->v2 && a->v4 == b->v3 && a->v1 == b->v4) {
1086 return 3;
1087 }
1088 }
1089 else {
1090 if (a->v1 == b->v1 && a->v2 == b->v2 && a->v3 == b->v3) {
1091 return 0;
1092 }
1093 if (a->v3 == b->v1 && a->v1 == b->v2 && a->v2 == b->v3) {
1094 return 1;
1095 }
1096 if (a->v2 == b->v1 && a->v3 == b->v2 && a->v1 == b->v3) {
1097 return 2;
1098 }
1099 }
1100
1101 return -1;
1102}
1103
1104static bool mirror_facecmp(const void *a, const void *b)
1105{
1106 return (mirror_facerotation((MFace *)a, (MFace *)b) == -1);
1107}
1108
1110{
1111 Mesh *mesh = static_cast<Mesh *>(ob->data);
1112 MFace mirrormf;
1113 const MFace *mf, *hashmf;
1114 GHash *fhash;
1115 int *mirrorverts, *mirrorfaces;
1116
1117 BLI_assert(em == nullptr); /* Does not work otherwise, currently... */
1118
1119 const bool use_topology = (mesh->editflag & ME_EDIT_MIRROR_TOPO) != 0;
1120 const int totvert = mesh_eval ? mesh_eval->verts_num : mesh->verts_num;
1121 const int totface = mesh_eval ? mesh_eval->totface_legacy : mesh->totface_legacy;
1122 int a;
1123
1124 mirrorverts = MEM_calloc_arrayN<int>(totvert, "MirrorVerts");
1125 mirrorfaces = MEM_calloc_arrayN<int>(2 * totface, "MirrorFaces");
1126
1127 const Span<float3> vert_positions = mesh_eval ? mesh_eval->vert_positions() :
1128 mesh->vert_positions();
1129 const MFace *mface = (const MFace *)CustomData_get_layer(
1130 &(mesh_eval ? mesh_eval : mesh)->fdata_legacy, CD_MFACE);
1131
1132 ED_mesh_mirror_spatial_table_begin(ob, em, mesh_eval);
1133
1134 for (const int i : vert_positions.index_range()) {
1135 mirrorverts[i] = mesh_get_x_mirror_vert(ob, mesh_eval, i, use_topology);
1136 }
1137
1139
1140 fhash = BLI_ghash_new_ex(
1141 mirror_facehash, mirror_facecmp, "mirror_facehash gh", mesh->totface_legacy);
1142 for (a = 0, mf = mface; a < totface; a++, mf++) {
1143 BLI_ghash_insert(fhash, (void *)mf, (void *)mf);
1144 }
1145
1146 for (a = 0, mf = mface; a < totface; a++, mf++) {
1147 mirrormf.v1 = mirrorverts[mf->v3];
1148 mirrormf.v2 = mirrorverts[mf->v2];
1149 mirrormf.v3 = mirrorverts[mf->v1];
1150 mirrormf.v4 = (mf->v4) ? mirrorverts[mf->v4] : 0;
1151
1152 /* make sure v4 is not 0 if a quad */
1153 if (mf->v4 && mirrormf.v4 == 0) {
1154 std::swap(mirrormf.v1, mirrormf.v3);
1155 std::swap(mirrormf.v2, mirrormf.v4);
1156 }
1157
1158 hashmf = static_cast<const MFace *>(BLI_ghash_lookup(fhash, &mirrormf));
1159 if (hashmf) {
1160 mirrorfaces[a * 2] = hashmf - mface;
1161 mirrorfaces[a * 2 + 1] = mirror_facerotation(&mirrormf, hashmf);
1162 }
1163 else {
1164 mirrorfaces[a * 2] = -1;
1165 }
1166 }
1167
1168 BLI_ghash_free(fhash, nullptr, nullptr);
1169 MEM_freeN(mirrorverts);
1170
1171 return mirrorfaces;
1172}
1173
1174/* Selection (vertex and face). */
1175
1176bool ED_mesh_pick_face(bContext *C, Object *ob, const int mval[2], uint dist_px, uint *r_index)
1177{
1178 Mesh *mesh = static_cast<Mesh *>(ob->data);
1179
1180 BLI_assert(mesh && GS(mesh->id.name) == ID_ME);
1181
1182 if (!mesh || mesh->faces_num == 0) {
1183 return false;
1184 }
1185
1189
1190 if (dist_px) {
1191 /* Sample rect to increase chances of selecting, so that when clicking
1192 * on an edge in the back-buffer, we can still select a face. */
1194 vc.depsgraph, vc.region, vc.v3d, mval, 1, mesh->faces_num + 1, &dist_px);
1195 }
1196 else {
1197 /* sample only on the exact position */
1198 *r_index = DRW_select_buffer_sample_point(vc.depsgraph, vc.region, vc.v3d, mval);
1199 }
1200
1201 if ((*r_index) == 0 || (*r_index) > uint(mesh->faces_num)) {
1202 return false;
1203 }
1204
1205 (*r_index)--;
1206
1207 return true;
1208}
1209
1211 /* context */
1212 ARegion *region,
1213 const float mval[2],
1214 /* mesh data (evaluated) */
1215 const blender::IndexRange face,
1216 const Span<float3> vert_positions,
1217 const int *corner_verts,
1218 /* return values */
1219 float *r_len_best,
1220 int *r_v_idx_best)
1221{
1222 for (int j = face.size(); j--;) {
1223 float sco[2];
1224 const int v_idx = corner_verts[face[j]];
1225 if (ED_view3d_project_float_object(region, vert_positions[v_idx], sco, V3D_PROJ_TEST_NOP) ==
1227 {
1228 const float len_test = len_manhattan_v2v2(mval, sco);
1229 if (len_test < *r_len_best) {
1230 *r_len_best = len_test;
1231 *r_v_idx_best = v_idx;
1232 }
1233 }
1234 }
1235}
1237 bContext *C, Object *ob, const int mval[2], uint dist_px, uint *r_index)
1238{
1240 uint face_index;
1241 Mesh *mesh = static_cast<Mesh *>(ob->data);
1242
1243 BLI_assert(mesh && GS(mesh->id.name) == ID_ME);
1244
1245 if (ED_mesh_pick_face(C, ob, mval, dist_px, &face_index)) {
1246 const Object *ob_eval = DEG_get_evaluated(depsgraph, ob);
1247 const Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob_eval);
1248 if (!mesh_eval) {
1249 return false;
1250 }
1251 ARegion *region = CTX_wm_region(C);
1252
1253 int v_idx_best = ORIGINDEX_NONE;
1254
1255 /* find the vert closest to 'mval' */
1256 const float mval_f[2] = {float(mval[0]), float(mval[1])};
1257 float len_best = FLT_MAX;
1258
1259 const Span<float3> vert_positions = mesh_eval->vert_positions();
1260 const blender::OffsetIndices faces = mesh_eval->faces();
1261 const Span<int> corner_verts = mesh_eval->corner_verts();
1262
1263 const int *index_mp_to_orig = (const int *)CustomData_get_layer(&mesh_eval->face_data,
1264 CD_ORIGINDEX);
1265
1266 /* tag all verts using this face */
1267 if (index_mp_to_orig) {
1268 for (const int i : faces.index_range()) {
1269 if (index_mp_to_orig[i] == face_index) {
1271 mval_f,
1272 faces[i],
1273 vert_positions,
1274 corner_verts.data(),
1275 &len_best,
1276 &v_idx_best);
1277 }
1278 }
1279 }
1280 else {
1281 if (face_index < faces.size()) {
1283 mval_f,
1284 faces[face_index],
1285 vert_positions,
1286 corner_verts.data(),
1287 &len_best,
1288 &v_idx_best);
1289 }
1290 }
1291
1292 /* Map the `dm` to `mesh`, setting the `r_index` if possible. */
1293 if (v_idx_best != ORIGINDEX_NONE) {
1294 const int *index_mv_to_orig = (const int *)CustomData_get_layer(&mesh_eval->vert_data,
1295 CD_ORIGINDEX);
1296 if (index_mv_to_orig) {
1297 v_idx_best = index_mv_to_orig[v_idx_best];
1298 }
1299 }
1300
1301 if ((v_idx_best != ORIGINDEX_NONE) && (v_idx_best < mesh->verts_num)) {
1302 *r_index = v_idx_best;
1303 return true;
1304 }
1305 }
1306
1307 return false;
1308}
1309
1310bool ED_mesh_pick_edge(bContext *C, Object *ob, const int mval[2], uint dist_px, uint *r_index)
1311{
1313 Mesh *mesh = static_cast<Mesh *>(ob->data);
1314
1315 BLI_assert(mesh && GS(mesh->id.name) == ID_ME);
1316
1317 if (!mesh || mesh->edges_num == 0) {
1318 return false;
1319 }
1320
1325
1326 uint edge_idx_best = ORIGINDEX_NONE;
1327
1328 if (dist_px) {
1329 /* Sample rect to increase chances of selecting, so that when clicking
1330 * on an edge in the back-buffer, we can still select a face. */
1332 vc.depsgraph, vc.region, vc.v3d, mval, 1, mesh->edges_num + 1, &dist_px);
1333 }
1334 else {
1335 /* sample only on the exact position */
1336 edge_idx_best = DRW_select_buffer_sample_point(vc.depsgraph, vc.region, vc.v3d, mval);
1337 }
1338
1339 if (edge_idx_best == 0 || edge_idx_best > uint(mesh->edges_num)) {
1340 return false;
1341 }
1342
1343 edge_idx_best--;
1344
1345 if (edge_idx_best != ORIGINDEX_NONE) {
1346 *r_index = edge_idx_best;
1347 return true;
1348 }
1349
1350 return false;
1351}
1352
1361 const float *mval_f; /* [2] */
1363
1364 /* runtime */
1367};
1368
1369static void ed_mesh_pick_vert__mapFunc(void *user_data,
1370 int index,
1371 const float co[3],
1372 const float /*no*/[3])
1373{
1374 VertPickData *data = static_cast<VertPickData *>(user_data);
1375 if (!data->hide_vert.is_empty() && data->hide_vert[index]) {
1376 return;
1377 }
1378 float sco[2];
1381 {
1382 const float len = len_manhattan_v2v2(data->mval_f, sco);
1383 if (len < data->len_best) {
1384 data->len_best = len;
1385 data->v_idx_best = index;
1386 }
1387 }
1388}
1390 bContext *C, Object *ob, const int mval[2], uint dist_px, bool use_zbuf, uint *r_index)
1391{
1392 using namespace blender;
1393 Mesh *mesh = static_cast<Mesh *>(ob->data);
1394
1395 BLI_assert(mesh && GS(mesh->id.name) == ID_ME);
1396
1397 if (!mesh || mesh->verts_num == 0) {
1398 return false;
1399 }
1400
1404
1405 if (use_zbuf) {
1406 if (dist_px > 0) {
1407 /* Sample rectangle to increase chances of selecting, so that when clicking
1408 * on an face in the back-buffer, we can still select a vert. */
1410 vc.depsgraph, vc.region, vc.v3d, mval, 1, mesh->verts_num + 1, &dist_px);
1411 }
1412 else {
1413 /* sample only on the exact position */
1414 *r_index = DRW_select_buffer_sample_point(vc.depsgraph, vc.region, vc.v3d, mval);
1415 }
1416
1417 if ((*r_index) == 0 || (*r_index) > uint(mesh->verts_num)) {
1418 return false;
1419 }
1420
1421 (*r_index)--;
1422 }
1423 else {
1424 const Object *ob_eval = DEG_get_evaluated(vc.depsgraph, ob);
1425 const Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob_eval);
1426 ARegion *region = vc.region;
1427 RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
1428
1429 /* find the vert closest to 'mval' */
1430 const float mval_f[2] = {float(mval[0]), float(mval[1])};
1431
1433
1434 ED_view3d_init_mats_rv3d(ob, rv3d);
1435
1436 if (mesh_eval == nullptr) {
1437 return false;
1438 }
1439
1440 const bke::AttributeAccessor attributes = mesh->attributes();
1441
1442 /* setup data */
1443 data.region = region;
1444 data.mval_f = mval_f;
1445 data.len_best = FLT_MAX;
1446 data.v_idx_best = -1;
1447 data.hide_vert = *attributes.lookup<bool>(".hide_vert", bke::AttrDomain::Point);
1448
1450
1451 if (data.v_idx_best == -1) {
1452 return false;
1453 }
1454
1455 *r_index = data.v_idx_best;
1456 }
1457
1458 return true;
1459}
1460
1462{
1463 if (ob->mode & OB_MODE_EDIT && ob->type == OB_MESH) {
1464 Mesh *mesh = static_cast<Mesh *>(ob->data);
1466 BMesh *bm = mesh->runtime->edit_mesh->bm;
1467 const int cd_dvert_offset = CustomData_get_offset(&bm->vdata, CD_MDEFORMVERT);
1468
1469 if (cd_dvert_offset != -1) {
1471
1472 if (eve) {
1473 if (r_eve) {
1474 *r_eve = eve;
1475 }
1476 return static_cast<MDeformVert *>(BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset));
1477 }
1478 }
1479 }
1480 }
1481
1482 if (r_eve) {
1483 *r_eve = nullptr;
1484 }
1485 return nullptr;
1486}
1487
1489{
1490 Mesh *mesh = static_cast<Mesh *>(ob->data);
1491 int index = BKE_mesh_mselect_active_get(mesh, ME_VSEL);
1492 if (r_index) {
1493 *r_index = index;
1494 }
1495 if (index == -1 || mesh->deform_verts().is_empty()) {
1496 return nullptr;
1497 }
1498 MutableSpan<MDeformVert> dverts = mesh->deform_verts_for_write();
1499 return &dverts[index];
1500}
1501
1503{
1504 if (ob->type == OB_MESH) {
1505 if (ob->mode & OB_MODE_EDIT) {
1506 return ED_mesh_active_dvert_get_em(ob, nullptr);
1507 }
1508 return ED_mesh_active_dvert_get_ob(ob, nullptr);
1509 }
1510 return nullptr;
1511}
1512
1513void EDBM_mesh_stats_multi(const Span<Object *> objects, int totelem[3], int totelem_sel[3])
1514{
1515 if (totelem) {
1516 totelem[0] = 0;
1517 totelem[1] = 0;
1518 totelem[2] = 0;
1519 }
1520 if (totelem_sel) {
1521 totelem_sel[0] = 0;
1522 totelem_sel[1] = 0;
1523 totelem_sel[2] = 0;
1524 }
1525
1526 for (Object *obedit : objects) {
1528 BMesh *bm = em->bm;
1529 if (totelem) {
1530 totelem[0] += bm->totvert;
1531 totelem[1] += bm->totedge;
1532 totelem[2] += bm->totface;
1533 }
1534 if (totelem_sel) {
1535 totelem_sel[0] += bm->totvertsel;
1536 totelem_sel[1] += bm->totedgesel;
1537 totelem_sel[2] += bm->totfacesel;
1538 }
1539 }
1540}
1541
1542void EDBM_mesh_elem_index_ensure_multi(const Span<Object *> objects, const char htype)
1543{
1544 int elem_offset[4] = {0, 0, 0, 0};
1545 for (Object *obedit : objects) {
1547 BMesh *bm = em->bm;
1548 BM_mesh_elem_index_ensure_ex(bm, htype, elem_offset);
1549 }
1550}
#define CTX_DATA_BEGIN(C, Type, instance, member)
Depsgraph * CTX_data_ensure_evaluated_depsgraph(const bContext *C)
Object * CTX_data_active_object(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
Main * CTX_data_main(const bContext *C)
ARegion * CTX_wm_region(const bContext *C)
#define CTX_DATA_END
CustomData interface, see also DNA_customdata_types.h.
int CustomData_get_offset(const CustomData *data, eCustomDataType type)
void * CustomData_get_layer_named_for_write(CustomData *data, eCustomDataType type, blender::StringRef name, int totelem)
const void * CustomData_get_layer(const CustomData *data, eCustomDataType type)
@ CD_SET_DEFAULT
@ CD_CONSTRUCT
void * CustomData_add_layer_named(CustomData *data, eCustomDataType type, eCDAllocType alloctype, int totelem, blender::StringRef name)
void CustomData_reset(CustomData *data)
#define ORIGINDEX_NONE
bool CustomData_merge_layout(const CustomData *source, CustomData *dest, eCustomDataMask mask, eCDAllocType alloctype, int totelem)
void CustomData_copy_data_named(const CustomData *source, CustomData *dest, int source_index, int dest_index, int count)
const CustomData_MeshMasks CD_MASK_MESH
void * CustomData_get_for_write(CustomData *data, int index, eCustomDataType type, int totelem)
support for deformation groups and hooks.
bDeformGroup * BKE_object_defgroup_find_name(const Object *ob, blender::StringRef name)
Definition deform.cc:515
BMEditMesh * BKE_editmesh_from_object(Object *ob)
Return the BMEditMesh for a given object.
Definition editmesh.cc:61
Key * BKE_key_add(Main *bmain, ID *id)
Definition key.cc:258
KeyBlock * BKE_keyblock_add(Key *key, const char *name)
Definition key.cc:1835
void BKE_keyblock_update_from_mesh(const Mesh *mesh, KeyBlock *kb)
Definition key.cc:2190
void BKE_keyblock_convert_from_mesh(const Mesh *mesh, const Key *key, KeyBlock *kb)
Definition key.cc:2203
void BKE_keyblock_copy_settings(KeyBlock *kb_dst, const KeyBlock *kb_src)
copy shape-key attributes, but not key data or name/UID.
Definition key.cc:1964
KeyBlock * BKE_keyblock_find_name(Key *key, const char name[])
Definition key.cc:1949
void BKE_key_sort(Key *key)
Definition key.cc:310
Base * BKE_view_layer_base_find(ViewLayer *view_layer, Object *ob)
@ LIB_ID_FREE_NO_UI_USER
void id_us_plus(ID *id)
Definition lib_id.cc:353
ID * BKE_id_copy(Main *bmain, const ID *id)
Definition lib_id.cc:772
const char * BKE_id_name(const ID &id)
void id_us_min(ID *id)
Definition lib_id.cc:361
void BKE_id_free_ex(Main *bmain, void *idv, int flag_orig, bool use_flag_from_idtag)
General operations, lookup, etc. for materials.
void BKE_objects_materials_sync_length_all(Main *bmain, ID *id)
Material * BKE_object_material_get(Object *ob, short act)
int BKE_mesh_mselect_active_get(const Mesh *mesh, int type)
Mesh * BKE_mesh_from_object(Object *ob)
void BKE_mesh_clear_geometry(Mesh *mesh)
@ 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)
void multiresModifier_prepare_join(Depsgraph *depsgraph, Scene *scene, Object *ob, Object *to_ob)
Definition multires.cc:1416
MultiresModifierData * get_multires_modifier(Scene *scene, Object *ob, bool use_first)
Definition multires.cc:296
General operations, lookup, etc. for blender objects.
void BKE_object_apply_mat4_ex(Object *ob, const float mat[4][4], Object *parent, const float parentinv[4][4], bool use_compat)
Mesh * BKE_object_get_evaluated_mesh(const Object *object_eval)
void BKE_object_free_derived_caches(Object *ob)
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)
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.cc:126
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_INLINE
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.cc:678
void * BLI_ghash_lookup(const GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.cc:731
void BLI_ghash_insert(GHash *gh, void *key, void *val)
Definition BLI_ghash.cc:707
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition BLI_ghash.cc:860
int BLI_findindex(const ListBase *listbase, const void *vlink) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:586
#define LISTBASE_FOREACH(type, var, list)
BLI_INLINE bool BLI_listbase_is_empty(const ListBase *lb)
void BLI_addtail(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:111
#define LISTBASE_FOREACH_INDEX(type, var, list, index_var)
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])
void mul_m4_v3(const float M[4][4], float r[3])
void invert_m4_m4_safe_ortho(float inverse[4][4], const float mat[4][4])
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
#define ELEM(...)
#define LIKELY(x)
float[3] Vector
void DEG_id_tag_update(ID *id, unsigned int flags)
void DEG_relations_tag_update(Main *bmain)
T * DEG_get_evaluated(const Depsgraph *depsgraph, T *id)
@ ID_RECALC_TRANSFORM
Definition DNA_ID.h:962
@ ID_RECALC_SELECT
Definition DNA_ID.h:1009
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:982
@ ID_ME
@ CD_PROP_FLOAT3
@ CD_PROP_INT32_2D
@ CD_MDEFORMVERT
@ CD_PROP_INT32
@ KEY_RELATIVE
#define MAXMAT
#define MESH_MAX_VERTS
@ ME_EDIT_MIRROR_TOPO
@ ME_VSEL
@ OB_MODE_EDIT
Object is a sort of wrapper for general info.
@ OB_MESH
@ SCE_SELECT_EDGE
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
void DRW_select_buffer_context_create(Depsgraph *depsgraph, blender::Span< Base * > bases, short select_mode)
uint DRW_select_buffer_sample_point(Depsgraph *depsgraph, ARegion *region, View3D *v3d, const int center[2])
uint DRW_select_buffer_find_nearest_to_point(Depsgraph *depsgraph, ARegion *region, View3D *v3d, const int center[2], uint id_min, uint id_max, uint *dist)
int ED_mesh_mirror_spatial_table_lookup(Object *ob, BMEditMesh *em, Mesh *mesh_eval, const float co[3])
void ED_mesh_mirror_spatial_table_begin(Object *ob, BMEditMesh *em, Mesh *mesh_eval)
void ED_mesh_mirrtopo_free(MirrTopoStore_t *mesh_topo_store)
void ED_mesh_mirror_spatial_table_end(Object *ob)
bool ED_mesh_mirrtopo_recalc_check(BMEditMesh *em, Mesh *mesh, MirrTopoStore_t *mesh_topo_store)
void ED_mesh_mirrtopo_init(BMEditMesh *em, Mesh *mesh, MirrTopoStore_t *mesh_topo_store, bool skip_em_vert_array_init)
@ V3D_PROJ_TEST_NOP
Definition ED_view3d.hh:279
eV3DProjStatus ED_view3d_project_float_object(const ARegion *region, const float co[3], float r_co[2], eV3DProjTest flag)
void ED_view3d_init_mats_rv3d(const Object *ob, RegionView3D *rv3d)
@ V3D_PROJ_RET_OK
Definition ED_view3d.hh:256
void ED_view3d_select_id_validate(const ViewContext *vc)
ViewContext ED_view3d_viewcontext_init(bContext *C, Depsgraph *depsgraph)
#define V3D_PROJ_TEST_CLIP_DEFAULT
Definition ED_view3d.hh:309
Read Guarded memory(de)allocation.
#define C
Definition RandGen.cpp:29
#define NC_GEOM
Definition WM_types.hh:390
#define ND_OB_ACTIVE
Definition WM_types.hh:437
#define ND_DATA
Definition WM_types.hh:506
#define NC_SCENE
Definition WM_types.hh:375
#define ND_LAYER_CONTENT
Definition WM_types.hh:450
ReportList * reports
Definition WM_types.hh:1025
#define BM_ELEM_CD_GET_FLOAT_P(ele, offset)
#define BM_ELEM_CD_GET_VOID_P(ele, offset)
#define BM_elem_index_get(ele)
#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
BMesh const char void * data
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])
BLI_INLINE BMVert * BM_vert_at_index(BMesh *bm, const int index)
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])
BPy_StructRNA * depsgraph
AttributeSet attributes
void append(const T &value)
bool is_empty() const
constexpr int64_t size() const
constexpr const T * data() const
Definition BLI_span.hh:215
constexpr IndexRange index_range() const
Definition BLI_span.hh:401
int64_t size() const
void append(const T &value)
GAttributeReader lookup(const StringRef attribute_id) const
GSpanAttributeWriter lookup_for_write_span(StringRef attribute_id)
#define fabsf(x)
#define isnan
#define cos
#define MEM_SAFE_FREE(v)
#define GS(a)
void * MEM_mallocN(size_t len, const char *str)
Definition mallocn.cc:128
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:123
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void * MEM_malloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:133
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
static char faces[256]
static bool mirror_facecmp(const void *a, const void *b)
void ED_mesh_mirror_topo_table_begin(Object *ob, Mesh *mesh_eval)
Definition meshtools.cc:858
MDeformVert * ED_mesh_active_dvert_get_em(Object *ob, BMVert **r_eve)
static uint mirror_facehash(const void *ptr)
wmOperatorStatus ED_mesh_shapes_join_objects_exec(bContext *C, const bool ensure_keys_exist, ReportList *reports)
Definition meshtools.cc:720
bool ED_mesh_pick_edge(bContext *C, Object *ob, const int mval[2], uint dist_px, uint *r_index)
wmOperatorStatus ED_mesh_join_objects_exec(bContext *C, wmOperator *op)
Definition meshtools.cc:339
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:972
static int mesh_get_x_mirror_vert_spatial(Object *ob, Mesh *mesh_eval, int index)
Definition meshtools.cc:888
int ED_mesh_mirror_get_vert(Object *ob, int index)
Definition meshtools.cc:981
int mesh_get_x_mirror_vert(Object *ob, Mesh *mesh_eval, int index, const bool use_topology)
Definition meshtools.cc:911
static void ed_mesh_pick_face_vert__mpoly_find(ARegion *region, const float mval[2], const blender::IndexRange face, const Span< float3 > vert_positions, const int *corner_verts, float *r_len_best, int *r_v_idx_best)
bool ED_mesh_pick_face_vert(bContext *C, Object *ob, const int mval[2], uint dist_px, uint *r_index)
void ED_mesh_mirror_topo_table_end(Object *)
Definition meshtools.cc:867
static BMVert * editbmesh_get_x_mirror_vert_spatial(Object *ob, BMEditMesh *em, const float co[3])
Definition meshtools.cc:919
static MirrTopoStore_t mesh_topo_store
Definition meshtools.cc:833
static BMVert * editbmesh_get_x_mirror_vert_topo(Object *ob, BMEditMesh *em, BMVert *eve, int index)
Definition meshtools.cc:940
static int mirror_facerotation(const MFace *a, const MFace *b)
int * mesh_get_x_mirror_faces(Object *ob, BMEditMesh *em, Mesh *mesh_eval)
static void ed_mesh_pick_vert__mapFunc(void *user_data, int index, const float co[3], const float[3])
static void join_mesh_single(Depsgraph *depsgraph, Main *bmain, Scene *scene, Object *ob_dst, Object *ob_src, const float imat[4][4], float3 **vert_positions_pp, blender::int2 **medge_pp, int **corner_verts_pp, int **corner_edges_pp, int *all_face_offsets, CustomData *vert_data, CustomData *edge_data, CustomData *ldata, CustomData *face_data, int totvert, int totedge, int totloop, int faces_num, Key *key, Key *nkey, blender::Vector< Material * > &matar, int *vertofs, int *edgeofs, int *loopofs, int *polyofs)
Definition meshtools.cc:73
bool ED_mesh_pick_face(bContext *C, Object *ob, const int mval[2], uint dist_px, uint *r_index)
static void mesh_join_offset_face_sets_ID(Mesh *mesh, int *face_set_offset)
Definition meshtools.cc:316
BLI_INLINE void mesh_mirror_topo_table_get_meshes(Object *ob, Mesh *mesh_eval, Mesh **r_mesh_mirror, BMEditMesh **r_em_mirror)
Definition meshtools.cc:835
void EDBM_mesh_stats_multi(const Span< Object * > objects, int totelem[3], int totelem_sel[3])
bool ED_mesh_pick_vert(bContext *C, Object *ob, const int mval[2], uint dist_px, bool use_zbuf, uint *r_index)
MDeformVert * ED_mesh_active_dvert_get_only(Object *ob)
static bool ed_mesh_mirror_topo_table_update(Object *ob, Mesh *mesh_eval)
Definition meshtools.cc:874
static int mesh_get_x_mirror_vert_topo(Object *ob, Mesh *mesh, int index)
Definition meshtools.cc:902
MDeformVert * ED_mesh_active_dvert_get_ob(Object *ob, int *r_index)
void EDBM_mesh_elem_index_ensure_multi(const Span< Object * > objects, const char htype)
bool iter_other(Main *bmain, Object *orig_ob, bool include_orig, bool(*callback)(Object *ob, void *callback_data), void *callback_data)
bool multires_update_totlevels(Object *ob, void *totlevel_v)
void base_free_and_unlink(Main *bmain, Scene *scene, Object *ob)
const ImplicitSharingInfo * info_for_mem_free(void *data)
VecBase< int32_t, 2 > int2
VecBase< float, 3 > float3
#define FLT_MAX
Definition stdcycles.h:14
void * regiondata
float co[3]
int totvert
Definition DNA_ID.h:404
char name[66]
Definition DNA_ID.h:415
short relative
void * data
int totkey
char type
ListBase block
unsigned int v2
unsigned int v1
unsigned int v4
unsigned int v3
int corners_num
CustomData edge_data
int edges_num
MeshRuntimeHandle * runtime
struct Material ** mat
CustomData corner_data
CustomData face_data
ListBase vertex_group_names
int * face_offset_indices
char editflag
CustomData vert_data
short totcol
int vertex_group_active_index
struct Key * key
int totface_legacy
int faces_num
int verts_num
ustring name
Definition graph/node.h:177
struct Material ** mat
char * matbits
float parentinv[4][4]
struct Object * parent
const float * mval_f
ARegion * region
blender::VArraySpan< bool > hide_vert
ARegion * region
Definition ED_view3d.hh:77
ViewLayer * view_layer
Definition ED_view3d.hh:74
View3D * v3d
Definition ED_view3d.hh:78
Object * obact
Definition ED_view3d.hh:75
Depsgraph * depsgraph
Definition ED_view3d.hh:72
struct ReportList * reports
i
Definition text_draw.cc:230
uint len
void WM_main_add_notifier(uint type, void *reference)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
PointerRNA * ptr
Definition wm_files.cc:4227