Blender V5.0
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_vector.h"
18#include "BLI_vector.hh"
19#include "BLI_virtual_array.hh"
20
21#include "DNA_key_types.h"
22#include "DNA_mesh_types.h"
23#include "DNA_meshdata_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_editmesh.hh"
33#include "BKE_key.hh"
34#include "BKE_layer.hh"
35#include "BKE_lib_id.hh"
36#include "BKE_material.hh"
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_paint.hh"
43#include "BKE_paint_bvh.hh"
44#include "BKE_report.hh"
45
46#include "DEG_depsgraph.hh"
49
50#include "DRW_select_buffer.hh"
51
52#include "ED_mesh.hh"
53#include "ED_object.hh"
54#include "ED_sculpt.hh"
55#include "ED_view3d.hh"
56
57#include "WM_api.hh"
58#include "WM_types.hh"
59
60#include "mesh_intern.hh"
61
62using blender::float3;
63using blender::int2;
65using blender::Span;
66
67/* -------------------------------------------------------------------- */
72
73static std::string create_mirrored_name(const blender::StringRefNull object_name,
74 const bool mirror)
75{
76 if (!mirror) {
77 return object_name;
78 }
79 if (object_name.endswith(".L")) {
80 return blender::StringRef(object_name).drop_suffix(2) + ".R";
81 }
82 if (object_name.endswith(".R")) {
83 return blender::StringRef(object_name).drop_suffix(2) + ".L";
84 }
85 return object_name;
86}
87
89 const bool ensure_keys_exist,
90 const bool mirror,
91 ReportList *reports)
92{
93 using namespace blender;
94 Main *bmain = CTX_data_main(C);
95 Object &active_object = *CTX_data_active_object(C);
97 Mesh &active_mesh = *static_cast<Mesh *>(active_object.data);
98
99 struct ObjectInfo {
101 const Mesh &mesh;
102 };
103
104 auto topology_count_matches = [](const Mesh &a, const Mesh &b) {
105 return a.verts_num == b.verts_num;
106 };
107
108 bool found_object = false;
109 bool found_non_equal_count = false;
110 Vector<ObjectInfo> compatible_objects;
111 CTX_DATA_BEGIN (C, Object *, ob_iter, selected_editable_objects) {
112 if (ob_iter == &active_object) {
113 continue;
114 }
115 if (ob_iter->type != OB_MESH) {
116 continue;
117 }
118 const Object *object_eval = DEG_get_evaluated(&depsgraph, ob_iter);
119 if (!object_eval) {
120 continue;
121 }
122 found_object = true;
123 if (const Mesh *mesh = BKE_object_get_evaluated_mesh(object_eval)) {
124 if (topology_count_matches(*mesh, active_mesh)) {
125 compatible_objects.append({BKE_id_name(ob_iter->id), *mesh});
126 continue;
127 }
128 }
129 /* Fall back to the original mesh. */
130 const Mesh &mesh_orig = *static_cast<const Mesh *>(ob_iter->data);
131 if (topology_count_matches(mesh_orig, active_mesh)) {
132 compatible_objects.append({BKE_id_name(ob_iter->id), mesh_orig});
133 continue;
134 }
135 found_non_equal_count = true;
136 }
138
139 if (!found_object) {
140 BKE_report(reports, RPT_WARNING, "No source mesh objects selected");
141 return OPERATOR_CANCELLED;
142 }
143
144 if (found_non_equal_count) {
145 BKE_report(reports, RPT_WARNING, "Selected meshes must have equal numbers of vertices");
146 return OPERATOR_CANCELLED;
147 }
148
149 if (compatible_objects.is_empty()) {
151 reports, RPT_WARNING, "No additional selected meshes with equal vertex count to join");
152 return OPERATOR_CANCELLED;
153 }
154
155 if (!active_mesh.key) {
156 /* Initialize basis shape key with existing mesh. */
157 active_mesh.key = BKE_key_add(bmain, &active_mesh.id);
158 active_mesh.key->type = KEY_RELATIVE;
160 &active_mesh, active_mesh.key, BKE_keyblock_add(active_mesh.key, nullptr));
161 }
162
163 if (mirror) {
164 for (const ObjectInfo &info : compatible_objects) {
165 if (!info.name.endswith(".L") && !info.name.endswith(".R")) {
166 BKE_report(reports, RPT_ERROR, "Selected objects' names must use .L or .R suffix");
167 return OPERATOR_CANCELLED;
168 }
169 }
170 }
171
172 int mirror_count = 0;
173 int mirror_fail_count = 0;
174 int keys_changed = 0;
175 bool any_keys_added = false;
176 for (const ObjectInfo &info : compatible_objects) {
177 const std::string name = create_mirrored_name(info.name, mirror);
178 if (ensure_keys_exist) {
179 KeyBlock *kb = BKE_keyblock_add(active_mesh.key, name.c_str());
180 BKE_keyblock_convert_from_mesh(&info.mesh, active_mesh.key, kb);
181 any_keys_added = true;
182 if (mirror) {
183 ed::object::shape_key_mirror(&active_object, kb, false, mirror_count, mirror_fail_count);
184 }
185 }
186 else if (KeyBlock *kb = BKE_keyblock_find_name(active_mesh.key, name.c_str())) {
187 keys_changed++;
188 BKE_keyblock_update_from_mesh(&info.mesh, kb);
189 if (mirror) {
190 ed::object::shape_key_mirror(&active_object, kb, false, mirror_count, mirror_fail_count);
191 }
192 }
193 }
194
195 if (!ensure_keys_exist) {
196 if (keys_changed == 0) {
197 BKE_report(reports, RPT_ERROR, "No name matches between selected objects and shape keys");
198 return OPERATOR_CANCELLED;
199 }
200 BKE_reportf(reports, RPT_INFO, "Updated %d shape key(s)", keys_changed);
201 }
202
203 if (mirror) {
204 ED_mesh_report_mirror_ex(*reports, mirror_count, mirror_fail_count, SCE_SELECT_VERTEX);
205 }
206
208 WM_main_add_notifier(NC_GEOM | ND_DATA, &active_mesh.id);
209
210 if (any_keys_added && bmain) {
211 /* Adding a new shape key should trigger a rebuild of relationships. */
213 }
214
215 return OPERATOR_FINISHED;
216}
217
219
220/* -------------------------------------------------------------------- */
223
224static MirrTopoStore_t mesh_topo_store = {nullptr, -1, -1, false};
225
227 Mesh *mesh_eval,
228 Mesh **r_mesh_mirror,
229 BMEditMesh **r_em_mirror)
230{
231 Mesh *mesh_mirror = nullptr;
232 BMEditMesh *em_mirror = nullptr;
233
234 Mesh *mesh = static_cast<Mesh *>(ob->data);
235 if (mesh_eval != nullptr) {
236 mesh_mirror = mesh_eval;
237 }
238 else if (BMEditMesh *em = mesh->runtime->edit_mesh.get()) {
239 em_mirror = em;
240 }
241 else {
242 mesh_mirror = mesh;
243 }
244
245 *r_mesh_mirror = mesh_mirror;
246 *r_em_mirror = em_mirror;
247}
248
250{
251 Mesh *mesh_mirror;
252 BMEditMesh *em_mirror;
253 mesh_mirror_topo_table_get_meshes(ob, mesh_eval, &mesh_mirror, &em_mirror);
254
255 ED_mesh_mirrtopo_init(em_mirror, mesh_mirror, &mesh_topo_store, false);
256}
257
259{
260 /* TODO: store this in object/object-data (keep unused argument for now). */
262}
263
264/* Returns true on success. */
265static bool ed_mesh_mirror_topo_table_update(Object *ob, Mesh *mesh_eval)
266{
267 Mesh *mesh_mirror;
268 BMEditMesh *em_mirror;
269 mesh_mirror_topo_table_get_meshes(ob, mesh_eval, &mesh_mirror, &em_mirror);
270
271 if (ED_mesh_mirrtopo_recalc_check(em_mirror, mesh_mirror, &mesh_topo_store)) {
272 ED_mesh_mirror_topo_table_begin(ob, mesh_eval);
273 }
274 return true;
275}
276
278
279static int mesh_get_x_mirror_vert_spatial(Object *ob, Mesh *mesh_eval, int index)
280{
281 Mesh *mesh = static_cast<Mesh *>(ob->data);
282 const Span<float3> positions = mesh_eval ? mesh_eval->vert_positions() : mesh->vert_positions();
283
284 float vec[3];
285
286 vec[0] = -positions[index][0];
287 vec[1] = positions[index][1];
288 vec[2] = positions[index][2];
289
290 return ED_mesh_mirror_spatial_table_lookup(ob, nullptr, mesh_eval, vec);
291}
292
293static int mesh_get_x_mirror_vert_topo(Object *ob, Mesh *mesh, int index)
294{
295 if (!ed_mesh_mirror_topo_table_update(ob, mesh)) {
296 return -1;
297 }
298
299 return mesh_topo_store.index_lookup[index];
300}
301
302int mesh_get_x_mirror_vert(Object *ob, Mesh *mesh_eval, int index, const bool use_topology)
303{
304 if (use_topology) {
305 return mesh_get_x_mirror_vert_topo(ob, mesh_eval, index);
306 }
307 return mesh_get_x_mirror_vert_spatial(ob, mesh_eval, index);
308}
309
311{
312 float vec[3];
313 int i;
314
315 /* ignore nan verts */
316 if ((isfinite(co[0]) == false) || (isfinite(co[1]) == false) || (isfinite(co[2]) == false)) {
317 return nullptr;
318 }
319
320 vec[0] = -co[0];
321 vec[1] = co[1];
322 vec[2] = co[2];
323
324 i = ED_mesh_mirror_spatial_table_lookup(ob, em, nullptr, vec);
325 if (i != -1) {
326 return BM_vert_at_index(em->bm, i);
327 }
328 return nullptr;
329}
330
332{
333 intptr_t poinval;
334 if (!ed_mesh_mirror_topo_table_update(ob, nullptr)) {
335 return nullptr;
336 }
337
338 if (index == -1) {
339 BMIter iter;
340 BMVert *v;
341
342 index = 0;
343 BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
344 if (v == eve) {
345 break;
346 }
347 index++;
348 }
349
350 if (index == em->bm->totvert) {
351 return nullptr;
352 }
353 }
354
355 poinval = mesh_topo_store.index_lookup[index];
356
357 if (poinval != -1) {
358 return (BMVert *)(poinval);
359 }
360 return nullptr;
361}
362
364 Object *ob, BMEditMesh *em, BMVert *eve, const float co[3], int index, const bool use_topology)
365{
366 if (use_topology) {
367 return editbmesh_get_x_mirror_vert_topo(ob, em, eve, index);
368 }
369 return editbmesh_get_x_mirror_vert_spatial(ob, em, co);
370}
371
373{
374 Mesh *mesh = static_cast<Mesh *>(ob->data);
375 bool use_topology = (mesh->editflag & ME_EDIT_MIRROR_TOPO) != 0;
376 int index_mirr;
377
378 if (BMEditMesh *em = mesh->runtime->edit_mesh.get()) {
379 BMVert *eve, *eve_mirr;
380 eve = BM_vert_at_index(em->bm, index);
381 eve_mirr = editbmesh_get_x_mirror_vert(ob, em, eve, eve->co, index, use_topology);
382 index_mirr = eve_mirr ? BM_elem_index_get(eve_mirr) : -1;
383 }
384 else {
385 index_mirr = mesh_get_x_mirror_vert(ob, nullptr, index, use_topology);
386 }
387
388 return index_mirr;
389}
390
391#if 0
392
393static float *editmesh_get_mirror_uv(
394 BMEditMesh *em, int axis, float *uv, float *mirrCent, float *face_cent)
395{
396 float vec[2];
397 float cent_vec[2];
398 float cent[2];
399
400 /* ignore nan verts */
401 if (isnan(uv[0]) || !isfinite(uv[0]) || isnan(uv[1]) || !isfinite(uv[1])) {
402 return nullptr;
403 }
404
405 if (axis) {
406 vec[0] = uv[0];
407 vec[1] = -((uv[1]) - mirrCent[1]) + mirrCent[1];
408
409 cent_vec[0] = face_cent[0];
410 cent_vec[1] = -((face_cent[1]) - mirrCent[1]) + mirrCent[1];
411 }
412 else {
413 vec[0] = -((uv[0]) - mirrCent[0]) + mirrCent[0];
414 vec[1] = uv[1];
415
416 cent_vec[0] = -((face_cent[0]) - mirrCent[0]) + mirrCent[0];
417 cent_vec[1] = face_cent[1];
418 }
419
420 /* TODO: Optimize. */
421 {
422 BMIter iter;
423 BMFace *efa;
424
425 BM_ITER_MESH (efa, &iter, em->bm, BM_FACES_OF_MESH) {
426 BM_face_uv_calc_center_median(efa, cd_loop_uv_offset, cent);
427
428 if ((fabsf(cent[0] - cent_vec[0]) < 0.001f) && (fabsf(cent[1] - cent_vec[1]) < 0.001f)) {
429 BMIter liter;
430 BMLoop *l;
431
432 BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
433 float *luv2 = BM_ELEM_CD_GET_FLOAT_P(l, cd_loop_uv_offset);
434 if ((fabsf(luv[0] - vec[0]) < 0.001f) && (fabsf(luv[1] - vec[1]) < 0.001f)) {
435 return luv;
436 }
437 }
438 }
439 }
440 }
441
442 return nullptr;
443}
444
445#endif
446
447static uint mirror_facehash(const void *ptr)
448{
449 const MFace *mf = static_cast<const MFace *>(ptr);
450 uint v0, v1;
451
452 if (mf->v4) {
453 v0 = std::min({mf->v1, mf->v2, mf->v3, mf->v4});
454 v1 = std::max({mf->v1, mf->v2, mf->v3, mf->v4});
455 }
456 else {
457 v0 = std::min({mf->v1, mf->v2, mf->v3});
458 v1 = std::min({mf->v1, mf->v2, mf->v3});
459 }
460
461 return ((v0 * 39) ^ (v1 * 31));
462}
463
464static int mirror_facerotation(const MFace *a, const MFace *b)
465{
466 if (b->v4) {
467 if (a->v1 == b->v1 && a->v2 == b->v2 && a->v3 == b->v3 && a->v4 == b->v4) {
468 return 0;
469 }
470 if (a->v4 == b->v1 && a->v1 == b->v2 && a->v2 == b->v3 && a->v3 == b->v4) {
471 return 1;
472 }
473 if (a->v3 == b->v1 && a->v4 == b->v2 && a->v1 == b->v3 && a->v2 == b->v4) {
474 return 2;
475 }
476 if (a->v2 == b->v1 && a->v3 == b->v2 && a->v4 == b->v3 && a->v1 == b->v4) {
477 return 3;
478 }
479 }
480 else {
481 if (a->v1 == b->v1 && a->v2 == b->v2 && a->v3 == b->v3) {
482 return 0;
483 }
484 if (a->v3 == b->v1 && a->v1 == b->v2 && a->v2 == b->v3) {
485 return 1;
486 }
487 if (a->v2 == b->v1 && a->v3 == b->v2 && a->v1 == b->v3) {
488 return 2;
489 }
490 }
491
492 return -1;
493}
494
495static bool mirror_facecmp(const void *a, const void *b)
496{
497 return (mirror_facerotation((MFace *)a, (MFace *)b) == -1);
498}
499
501{
502 Mesh *mesh = static_cast<Mesh *>(ob->data);
503 MFace mirrormf;
504 const MFace *mf, *hashmf;
505 GHash *fhash;
506 int *mirrorverts, *mirrorfaces;
507
508 BLI_assert(em == nullptr); /* Does not work otherwise, currently... */
509
510 const bool use_topology = (mesh->editflag & ME_EDIT_MIRROR_TOPO) != 0;
511 const int totvert = mesh_eval ? mesh_eval->verts_num : mesh->verts_num;
512 const int totface = mesh_eval ? mesh_eval->totface_legacy : mesh->totface_legacy;
513 int a;
514
515 mirrorverts = MEM_calloc_arrayN<int>(totvert, "MirrorVerts");
516 mirrorfaces = MEM_calloc_arrayN<int>(2 * totface, "MirrorFaces");
517
518 const Span<float3> vert_positions = mesh_eval ? mesh_eval->vert_positions() :
519 mesh->vert_positions();
520 const MFace *mface = (const MFace *)CustomData_get_layer(
521 &(mesh_eval ? mesh_eval : mesh)->fdata_legacy, CD_MFACE);
522
523 ED_mesh_mirror_spatial_table_begin(ob, em, mesh_eval);
524
525 for (const int i : vert_positions.index_range()) {
526 mirrorverts[i] = mesh_get_x_mirror_vert(ob, mesh_eval, i, use_topology);
527 }
528
530
531 fhash = BLI_ghash_new_ex(
532 mirror_facehash, mirror_facecmp, "mirror_facehash gh", mesh->totface_legacy);
533 for (a = 0, mf = mface; a < totface; a++, mf++) {
534 BLI_ghash_insert(fhash, (void *)mf, (void *)mf);
535 }
536
537 for (a = 0, mf = mface; a < totface; a++, mf++) {
538 mirrormf.v1 = mirrorverts[mf->v3];
539 mirrormf.v2 = mirrorverts[mf->v2];
540 mirrormf.v3 = mirrorverts[mf->v1];
541 mirrormf.v4 = (mf->v4) ? mirrorverts[mf->v4] : 0;
542
543 /* make sure v4 is not 0 if a quad */
544 if (mf->v4 && mirrormf.v4 == 0) {
545 std::swap(mirrormf.v1, mirrormf.v3);
546 std::swap(mirrormf.v2, mirrormf.v4);
547 }
548
549 hashmf = static_cast<const MFace *>(BLI_ghash_lookup(fhash, &mirrormf));
550 if (hashmf) {
551 mirrorfaces[a * 2] = hashmf - mface;
552 mirrorfaces[a * 2 + 1] = mirror_facerotation(&mirrormf, hashmf);
553 }
554 else {
555 mirrorfaces[a * 2] = -1;
556 }
557 }
558
559 BLI_ghash_free(fhash, nullptr, nullptr);
560 MEM_freeN(mirrorverts);
561
562 return mirrorfaces;
563}
564
565/* Selection (vertex and face). */
566
567bool ED_mesh_pick_face(bContext *C, Object *ob, const int mval[2], uint dist_px, uint *r_index)
568{
569 Mesh *mesh = static_cast<Mesh *>(ob->data);
570
571 BLI_assert(mesh && GS(mesh->id.name) == ID_ME);
572
573 if (!mesh || mesh->faces_num == 0) {
574 return false;
575 }
576
580
581 if (dist_px) {
582 /* Sample rect to increase chances of selecting, so that when clicking
583 * on an edge in the back-buffer, we can still select a face. */
585 vc.depsgraph, vc.region, vc.v3d, mval, 1, mesh->faces_num + 1, &dist_px);
586 }
587 else {
588 /* sample only on the exact position */
589 *r_index = DRW_select_buffer_sample_point(vc.depsgraph, vc.region, vc.v3d, mval);
590 }
591
592 if ((*r_index) == 0 || (*r_index) > uint(mesh->faces_num)) {
593 return false;
594 }
595
596 (*r_index)--;
597
598 return true;
599}
600
602 /* context */
603 ARegion *region,
604 const float mval[2],
605 /* mesh data (evaluated) */
606 const blender::IndexRange face,
607 const Span<float3> vert_positions,
608 const int *corner_verts,
609 /* return values */
610 float *r_len_best,
611 int *r_v_idx_best)
612{
613 for (int j = face.size(); j--;) {
614 float sco[2];
615 const int v_idx = corner_verts[face[j]];
616 if (ED_view3d_project_float_object(region, vert_positions[v_idx], sco, V3D_PROJ_TEST_NOP) ==
618 {
619 const float len_test = len_manhattan_v2v2(mval, sco);
620 if (len_test < *r_len_best) {
621 *r_len_best = len_test;
622 *r_v_idx_best = v_idx;
623 }
624 }
625 }
626}
628 bContext *C, Object *ob, const int mval[2], uint dist_px, uint *r_index)
629{
631 uint face_index;
632 Mesh *mesh = static_cast<Mesh *>(ob->data);
633
634 BLI_assert(mesh && GS(mesh->id.name) == ID_ME);
635
636 if (ED_mesh_pick_face(C, ob, mval, dist_px, &face_index)) {
637 const Object *ob_eval = DEG_get_evaluated(depsgraph, ob);
638 const Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob_eval);
639 if (!mesh_eval) {
640 return false;
641 }
642 ARegion *region = CTX_wm_region(C);
643
644 int v_idx_best = ORIGINDEX_NONE;
645
646 /* find the vert closest to 'mval' */
647 const float mval_f[2] = {float(mval[0]), float(mval[1])};
648 float len_best = FLT_MAX;
649
650 const Span<float3> vert_positions = mesh_eval->vert_positions();
651 const blender::OffsetIndices faces = mesh_eval->faces();
652 const Span<int> corner_verts = mesh_eval->corner_verts();
653
654 const int *index_mp_to_orig = (const int *)CustomData_get_layer(&mesh_eval->face_data,
656
657 /* tag all verts using this face */
658 if (index_mp_to_orig) {
659 for (const int i : faces.index_range()) {
660 if (index_mp_to_orig[i] == face_index) {
662 mval_f,
663 faces[i],
664 vert_positions,
665 corner_verts.data(),
666 &len_best,
667 &v_idx_best);
668 }
669 }
670 }
671 else {
672 if (face_index < faces.size()) {
674 mval_f,
675 faces[face_index],
676 vert_positions,
677 corner_verts.data(),
678 &len_best,
679 &v_idx_best);
680 }
681 }
682
683 /* Map the `dm` to `mesh`, setting the `r_index` if possible. */
684 if (v_idx_best != ORIGINDEX_NONE) {
685 const int *index_mv_to_orig = (const int *)CustomData_get_layer(&mesh_eval->vert_data,
687 if (index_mv_to_orig) {
688 v_idx_best = index_mv_to_orig[v_idx_best];
689 }
690 }
691
692 if ((v_idx_best != ORIGINDEX_NONE) && (v_idx_best < mesh->verts_num)) {
693 *r_index = v_idx_best;
694 return true;
695 }
696 }
697
698 return false;
699}
700
701bool ED_mesh_pick_edge(bContext *C, Object *ob, const int mval[2], uint dist_px, uint *r_index)
702{
704 Mesh *mesh = static_cast<Mesh *>(ob->data);
705
706 BLI_assert(mesh && GS(mesh->id.name) == ID_ME);
707
708 if (!mesh || mesh->edges_num == 0) {
709 return false;
710 }
711
716
717 uint edge_idx_best = ORIGINDEX_NONE;
718
719 if (dist_px) {
720 /* Sample rect to increase chances of selecting, so that when clicking
721 * on an edge in the back-buffer, we can still select a face. */
723 vc.depsgraph, vc.region, vc.v3d, mval, 1, mesh->edges_num + 1, &dist_px);
724 }
725 else {
726 /* sample only on the exact position */
727 edge_idx_best = DRW_select_buffer_sample_point(vc.depsgraph, vc.region, vc.v3d, mval);
728 }
729
730 if (edge_idx_best == 0 || edge_idx_best > uint(mesh->edges_num)) {
731 return false;
732 }
733
734 edge_idx_best--;
735
736 if (edge_idx_best != ORIGINDEX_NONE) {
737 *r_index = edge_idx_best;
738 return true;
739 }
740
741 return false;
742}
743
752 const float *mval_f; /* [2] */
754
755 /* runtime */
756 float len_best;
758};
759
760static void ed_mesh_pick_vert__mapFunc(void *user_data,
761 int index,
762 const float co[3],
763 const float /*no*/[3])
764{
765 VertPickData *data = static_cast<VertPickData *>(user_data);
766 if (!data->hide_vert.is_empty() && data->hide_vert[index]) {
767 return;
768 }
769 float sco[2];
772 {
773 const float len = len_manhattan_v2v2(data->mval_f, sco);
774 if (len < data->len_best) {
775 data->len_best = len;
776 data->v_idx_best = index;
777 }
778 }
779}
781 bContext *C, Object *ob, const int mval[2], uint dist_px, bool use_zbuf, uint *r_index)
782{
783 using namespace blender;
784 Mesh *mesh = static_cast<Mesh *>(ob->data);
785
786 BLI_assert(mesh && GS(mesh->id.name) == ID_ME);
787
788 if (!mesh || mesh->verts_num == 0) {
789 return false;
790 }
791
795
796 if (use_zbuf) {
797 if (dist_px > 0) {
798 /* Sample rectangle to increase chances of selecting, so that when clicking
799 * on an face in the back-buffer, we can still select a vert. */
801 vc.depsgraph, vc.region, vc.v3d, mval, 1, mesh->verts_num + 1, &dist_px);
802 }
803 else {
804 /* sample only on the exact position */
805 *r_index = DRW_select_buffer_sample_point(vc.depsgraph, vc.region, vc.v3d, mval);
806 }
807
808 if ((*r_index) == 0 || (*r_index) > uint(mesh->verts_num)) {
809 return false;
810 }
811
812 (*r_index)--;
813 }
814 else {
815 const Object *ob_eval = DEG_get_evaluated(vc.depsgraph, ob);
816 const Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob_eval);
817 ARegion *region = vc.region;
818 RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata);
819
820 /* find the vert closest to 'mval' */
821 const float mval_f[2] = {float(mval[0]), float(mval[1])};
822
824
825 ED_view3d_init_mats_rv3d(ob, rv3d);
826
827 if (mesh_eval == nullptr) {
828 return false;
829 }
830
831 const bke::AttributeAccessor attributes = mesh->attributes();
832
833 /* setup data */
834 data.region = region;
835 data.mval_f = mval_f;
836 data.len_best = FLT_MAX;
837 data.v_idx_best = -1;
838 data.hide_vert = *attributes.lookup<bool>(".hide_vert", bke::AttrDomain::Point);
839
841
842 if (data.v_idx_best == -1) {
843 return false;
844 }
845
846 *r_index = data.v_idx_best;
847 }
848
849 return true;
850}
851
853{
854 if (ob->mode & OB_MODE_EDIT && ob->type == OB_MESH) {
855 Mesh *mesh = static_cast<Mesh *>(ob->data);
857 BMesh *bm = mesh->runtime->edit_mesh->bm;
858 const int cd_dvert_offset = CustomData_get_offset(&bm->vdata, CD_MDEFORMVERT);
859
860 if (cd_dvert_offset != -1) {
862
863 if (eve) {
864 if (r_eve) {
865 *r_eve = eve;
866 }
867 return static_cast<MDeformVert *>(BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset));
868 }
869 }
870 }
871 }
872
873 if (r_eve) {
874 *r_eve = nullptr;
875 }
876 return nullptr;
877}
878
880{
881 Mesh *mesh = static_cast<Mesh *>(ob->data);
882 int index = BKE_mesh_mselect_active_get(mesh, ME_VSEL);
883 if (r_index) {
884 *r_index = index;
885 }
886 if (index == -1 || mesh->deform_verts().is_empty()) {
887 return nullptr;
888 }
889 MutableSpan<MDeformVert> dverts = mesh->deform_verts_for_write();
890 return &dverts[index];
891}
892
894{
895 if (ob->type == OB_MESH) {
896 if (ob->mode & OB_MODE_EDIT) {
897 return ED_mesh_active_dvert_get_em(ob, nullptr);
898 }
899 return ED_mesh_active_dvert_get_ob(ob, nullptr);
900 }
901 return nullptr;
902}
903
904void EDBM_mesh_stats_multi(const Span<Object *> objects, int totelem[3], int totelem_sel[3])
905{
906 if (totelem) {
907 totelem[0] = 0;
908 totelem[1] = 0;
909 totelem[2] = 0;
910 }
911 if (totelem_sel) {
912 totelem_sel[0] = 0;
913 totelem_sel[1] = 0;
914 totelem_sel[2] = 0;
915 }
916
917 for (Object *obedit : objects) {
919 BMesh *bm = em->bm;
920 if (totelem) {
921 totelem[0] += bm->totvert;
922 totelem[1] += bm->totedge;
923 totelem[2] += bm->totface;
924 }
925 if (totelem_sel) {
926 totelem_sel[0] += bm->totvertsel;
927 totelem_sel[1] += bm->totedgesel;
928 totelem_sel[2] += bm->totfacesel;
929 }
930 }
931}
932
933void EDBM_mesh_elem_index_ensure_multi(const Span<Object *> objects, const char htype)
934{
935 int elem_offset[4] = {0, 0, 0, 0};
936 for (Object *obedit : objects) {
938 BMesh *bm = em->bm;
939 BM_mesh_elem_index_ensure_ex(bm, htype, elem_offset);
940 }
941}
943{
945
946 Mesh *mesh = static_cast<Mesh *>(ob->data);
947 Scene *scene = CTX_data_scene(C);
948
949 if (ob->mode == OB_MODE_SCULPT && mesh->flag & ME_SCULPT_DYNAMIC_TOPOLOGY) {
950 /* Dyntopo not supported. */
951 BKE_report(op->reports, RPT_INFO, "Not supported in dynamic topology sculpting");
952 return OPERATOR_CANCELLED;
953 }
954
955 if (mesh->faces_num == 0 || mesh->verts_num == 0) {
956 return OPERATOR_CANCELLED;
957 }
958
959 if (ob->mode == OB_MODE_SCULPT) {
961 }
962
964
965 if (ob->mode == OB_MODE_SCULPT) {
967 }
968
971
972 BKE_report(op->reports, RPT_INFO, "Mesh faces and vertices reordered spatially");
973
974 return OPERATOR_FINISHED;
975}
976
978{
980 if (!ob || ob->type != OB_MESH) {
981 return false;
982 }
983
984 return true;
985}
986
988{
989 ot->name = "Reorder Mesh Spatially";
990 ot->idname = "MESH_OT_reorder_vertices_spatial";
991 ot->description =
992 "Reorder mesh faces and vertices based on their spatial position for better BVH building "
993 "and sculpting performance.";
994
997
999}
#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)
const void * CustomData_get_layer(const CustomData *data, eCustomDataType type)
#define ORIGINDEX_NONE
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:225
KeyBlock * BKE_keyblock_add(Key *key, const char *name)
Definition key.cc:1802
void BKE_keyblock_update_from_mesh(const Mesh *mesh, KeyBlock *kb)
Definition key.cc:2157
void BKE_keyblock_convert_from_mesh(const Mesh *mesh, const Key *key, KeyBlock *kb)
Definition key.cc:2170
KeyBlock * BKE_keyblock_find_name(Key *key, const char name[])
Definition key.cc:1916
Base * BKE_view_layer_base_find(ViewLayer *view_layer, Object *ob)
const char * BKE_id_name(const ID &id)
General operations, lookup, etc. for materials.
int BKE_mesh_mselect_active_get(const Mesh *mesh, int type)
@ MESH_FOREACH_NOP
void BKE_mesh_foreach_mapped_vert(const Mesh *mesh, void(*func)(void *user_data, int index, const float co[3], const float no[3]), void *user_data, MeshForeachFlag flag)
General operations, lookup, etc. for blender objects.
Mesh * BKE_object_get_evaluated_mesh(const Object *object_eval)
A BVH for high poly meshes.
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
@ RPT_INFO
Definition BKE_report.hh:35
@ RPT_ERROR
Definition BKE_report.hh:39
@ RPT_WARNING
Definition BKE_report.hh:38
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition report.cc:153
#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
BLI_INLINE bool BLI_listbase_is_empty(const ListBase *lb)
MINLINE float len_manhattan_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT
unsigned int uint
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_GEOMETRY
Definition DNA_ID.h:1074
@ ID_ME
@ CD_MDEFORMVERT
@ KEY_RELATIVE
@ ME_EDIT_MIRROR_TOPO
@ ME_SCULPT_DYNAMIC_TOPOLOGY
@ ME_VSEL
@ OB_MODE_EDIT
@ OB_MODE_SCULPT
Object is a sort of wrapper for general info.
@ OB_MESH
@ SCE_SELECT_VERTEX
@ 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_report_mirror_ex(ReportList &reports, int totmirr, int totfail, char selectmode)
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:393
#define ND_DATA
Definition WM_types.hh:509
@ OPTYPE_UNDO
Definition WM_types.hh:182
@ OPTYPE_REGISTER
Definition WM_types.hh:180
#define ND_MODIFIER
Definition WM_types.hh:462
#define NC_OBJECT
Definition WM_types.hh:379
#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
constexpr bool endswith(StringRef suffix) const
constexpr StringRef drop_suffix(int64_t n) const
GAttributeReader lookup(const StringRef attribute_id) const
nullptr float
#define GS(x)
#define isnan
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:123
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
static char faces[256]
static bool mirror_facecmp(const void *a, const void *b)
Definition meshtools.cc:495
void ED_mesh_mirror_topo_table_begin(Object *ob, Mesh *mesh_eval)
Definition meshtools.cc:249
MDeformVert * ED_mesh_active_dvert_get_em(Object *ob, BMVert **r_eve)
Definition meshtools.cc:852
static uint mirror_facehash(const void *ptr)
Definition meshtools.cc:447
bool ED_mesh_pick_edge(bContext *C, Object *ob, const int mval[2], uint dist_px, uint *r_index)
Definition meshtools.cc:701
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:363
static std::string create_mirrored_name(const blender::StringRefNull object_name, const bool mirror)
Definition meshtools.cc:73
static int mesh_get_x_mirror_vert_spatial(Object *ob, Mesh *mesh_eval, int index)
Definition meshtools.cc:279
int ED_mesh_mirror_get_vert(Object *ob, int index)
Definition meshtools.cc:372
int mesh_get_x_mirror_vert(Object *ob, Mesh *mesh_eval, int index, const bool use_topology)
Definition meshtools.cc:302
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)
Definition meshtools.cc:601
bool ED_mesh_pick_face_vert(bContext *C, Object *ob, const int mval[2], uint dist_px, uint *r_index)
Definition meshtools.cc:627
static bool mesh_reorder_vertices_spatial_poll(bContext *C)
Definition meshtools.cc:977
void ED_mesh_mirror_topo_table_end(Object *)
Definition meshtools.cc:258
static BMVert * editbmesh_get_x_mirror_vert_spatial(Object *ob, BMEditMesh *em, const float co[3])
Definition meshtools.cc:310
static MirrTopoStore_t mesh_topo_store
Definition meshtools.cc:224
static BMVert * editbmesh_get_x_mirror_vert_topo(Object *ob, BMEditMesh *em, BMVert *eve, int index)
Definition meshtools.cc:331
static int mirror_facerotation(const MFace *a, const MFace *b)
Definition meshtools.cc:464
int * mesh_get_x_mirror_faces(Object *ob, BMEditMesh *em, Mesh *mesh_eval)
Definition meshtools.cc:500
static void ed_mesh_pick_vert__mapFunc(void *user_data, int index, const float co[3], const float[3])
Definition meshtools.cc:760
void MESH_OT_reorder_vertices_spatial(wmOperatorType *ot)
Definition meshtools.cc:987
wmOperatorStatus ED_mesh_shapes_join_objects_exec(bContext *C, const bool ensure_keys_exist, const bool mirror, ReportList *reports)
Definition meshtools.cc:88
bool ED_mesh_pick_face(bContext *C, Object *ob, const int mval[2], uint dist_px, uint *r_index)
Definition meshtools.cc:567
static wmOperatorStatus mesh_reorder_vertices_spatial_exec(bContext *C, wmOperator *op)
Definition meshtools.cc:942
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:226
void EDBM_mesh_stats_multi(const Span< Object * > objects, int totelem[3], int totelem_sel[3])
Definition meshtools.cc:904
bool ED_mesh_pick_vert(bContext *C, Object *ob, const int mval[2], uint dist_px, bool use_zbuf, uint *r_index)
Definition meshtools.cc:780
MDeformVert * ED_mesh_active_dvert_get_only(Object *ob)
Definition meshtools.cc:893
static bool ed_mesh_mirror_topo_table_update(Object *ob, Mesh *mesh_eval)
Definition meshtools.cc:265
static int mesh_get_x_mirror_vert_topo(Object *ob, Mesh *mesh, int index)
Definition meshtools.cc:293
MDeformVert * ED_mesh_active_dvert_get_ob(Object *ob, int *r_index)
Definition meshtools.cc:879
void EDBM_mesh_elem_index_ensure_multi(const Span< Object * > objects, const char htype)
Definition meshtools.cc:933
void mesh_apply_spatial_organization(Mesh &mesh)
Object * context_active_object(const bContext *C)
void shape_key_mirror(Object *ob, KeyBlock *kb, bool use_topology, int &totmirr, int &totfail)
void geometry_begin(const Scene &scene, Object &ob, const wmOperator *op)
VecBase< int32_t, 2 > int2
VecBase< float, 3 > float3
const char * name
#define fabsf
#define FLT_MAX
Definition stdcycles.h:14
void * regiondata
float co[3]
int totvert
char name[258]
Definition DNA_ID.h:432
char type
unsigned int v2
unsigned int v1
unsigned int v4
unsigned int v3
int edges_num
MeshRuntimeHandle * runtime
uint16_t flag
CustomData face_data
ListBase vertex_group_names
char editflag
CustomData vert_data
struct Key * key
int totface_legacy
int faces_num
int verts_num
const float * mval_f
Definition meshtools.cc:752
ARegion * region
Definition meshtools.cc:753
blender::VArraySpan< bool > hide_vert
Definition meshtools.cc:751
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:4238
wmOperatorType * ot
Definition wm_files.cc:4237