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