Blender  V2.93
editmesh_utils.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2004 by Blender Foundation.
17  * All rights reserved.
18  */
19 
24 #include "MEM_guardedalloc.h"
25 
26 #include "DNA_key_types.h"
27 #include "DNA_mesh_types.h"
28 #include "DNA_object_types.h"
29 
30 #include "BLI_alloca.h"
31 #include "BLI_buffer.h"
32 #include "BLI_kdtree.h"
33 #include "BLI_listbase.h"
34 #include "BLI_math.h"
35 
36 #include "BKE_DerivedMesh.h"
37 #include "BKE_context.h"
38 #include "BKE_editmesh.h"
39 #include "BKE_editmesh_bvh.h"
40 #include "BKE_global.h"
41 #include "BKE_layer.h"
42 #include "BKE_main.h"
43 #include "BKE_mesh.h"
44 #include "BKE_mesh_mapping.h"
45 #include "BKE_report.h"
46 
47 #include "DEG_depsgraph.h"
48 
49 #include "BKE_object.h" /* XXX. only for EDBM_mesh_load(). */
50 
51 #include "WM_api.h"
52 #include "WM_types.h"
53 
54 #include "ED_mesh.h"
55 #include "ED_screen.h"
57 #include "ED_uvedit.h"
58 #include "ED_view3d.h"
59 
60 #include "mesh_intern.h" /* own include */
61 
62 /* -------------------------------------------------------------------- */
66 /* Mesh backup implementation.
67  * This would greatly benefit from some sort of binary diffing
68  * just as the undo stack would.
69  * So leaving this as an interface for further work */
70 
72 {
74  backup.bmcopy = BM_mesh_copy(em->bm);
75  return backup;
76 }
77 
79 {
80  BMesh *tmpbm;
81  if (!em || !backup.bmcopy) {
82  return;
83  }
84 
85  BM_mesh_data_free(em->bm);
86  tmpbm = BM_mesh_copy(backup.bmcopy);
87  *em->bm = *tmpbm;
88  MEM_freeN(tmpbm);
89  tmpbm = NULL;
90 
91  if (recalctess) {
93  }
94 }
95 
96 void EDBM_redo_state_free(BMBackup *backup, BMEditMesh *em, int recalctess)
97 {
98  if (em && backup->bmcopy) {
99  BM_mesh_data_free(em->bm);
100  *em->bm = *backup->bmcopy;
101  }
102  else if (backup->bmcopy) {
103  BM_mesh_data_free(backup->bmcopy);
104  }
105 
106  if (backup->bmcopy) {
107  MEM_freeN(backup->bmcopy);
108  }
109  backup->bmcopy = NULL;
110 
111  if (recalctess && em) {
113  }
114 }
115 
118 /* -------------------------------------------------------------------- */
122 bool EDBM_op_init(BMEditMesh *em, BMOperator *bmop, wmOperator *op, const char *fmt, ...)
123 {
124  BMesh *bm = em->bm;
125  va_list list;
126 
127  va_start(list, fmt);
128 
129  if (!BMO_op_vinitf(bm, bmop, BMO_FLAG_DEFAULTS, fmt, list)) {
130  BKE_reportf(op->reports, RPT_ERROR, "Parse error in %s", __func__);
131  va_end(list);
132  return false;
133  }
134 
135  if (!em->emcopy) {
136  em->emcopy = BKE_editmesh_copy(em);
137  }
138  em->emcopyusers++;
139 
140  va_end(list);
141 
142  return true;
143 }
144 
145 /* returns 0 on error, 1 on success. executes and finishes a bmesh operator */
146 bool EDBM_op_finish(BMEditMesh *em, BMOperator *bmop, wmOperator *op, const bool do_report)
147 {
148  const char *errmsg;
149 
150  BMO_op_finish(em->bm, bmop);
151 
152  if (BMO_error_get(em->bm, &errmsg, NULL)) {
153  BMEditMesh *emcopy = em->emcopy;
154 
155  if (do_report) {
156  BKE_report(op->reports, RPT_ERROR, errmsg);
157  }
158 
159  EDBM_mesh_free(em);
160  *em = *emcopy;
161 
162  MEM_freeN(emcopy);
163  em->emcopyusers = 0;
164  em->emcopy = NULL;
165 
173  {
174  Main *bmain = G_MAIN;
175  for (Mesh *mesh = bmain->meshes.first; mesh; mesh = mesh->id.next) {
176  if (mesh->edit_mesh == em) {
178  break;
179  }
180  }
181  }
182 
183  /* when copying, tessellation isn't to for faster copying,
184  * but means we need to re-tessellate here */
185  if (em->looptris == NULL) {
187  }
188 
189  return false;
190  }
191 
192  em->emcopyusers--;
193  if (em->emcopyusers < 0) {
194  printf("warning: em->emcopyusers was less than zero.\n");
195  }
196 
197  if (em->emcopyusers <= 0) {
199  MEM_freeN(em->emcopy);
200  em->emcopy = NULL;
201  }
202 
203  return true;
204 }
205 
206 bool EDBM_op_callf(BMEditMesh *em, wmOperator *op, const char *fmt, ...)
207 {
208  BMesh *bm = em->bm;
209  BMOperator bmop;
210  va_list list;
211 
212  va_start(list, fmt);
213 
214  if (!BMO_op_vinitf(bm, &bmop, BMO_FLAG_DEFAULTS, fmt, list)) {
215  BKE_reportf(op->reports, RPT_ERROR, "Parse error in %s", __func__);
216  va_end(list);
217  return false;
218  }
219 
220  if (!em->emcopy) {
221  em->emcopy = BKE_editmesh_copy(em);
222  }
223  em->emcopyusers++;
224 
225  BMO_op_exec(bm, &bmop);
226 
227  va_end(list);
228  return EDBM_op_finish(em, &bmop, op, true);
229 }
230 
232  wmOperator *op,
233  const char *select_slot_out,
234  const bool select_extend,
235  const char *fmt,
236  ...)
237 {
238  BMOpSlot *slot_select_out;
239  BMesh *bm = em->bm;
240  BMOperator bmop;
241  va_list list;
242  char hflag;
243 
244  va_start(list, fmt);
245 
246  if (!BMO_op_vinitf(bm, &bmop, BMO_FLAG_DEFAULTS, fmt, list)) {
247  BKE_reportf(op->reports, RPT_ERROR, "Parse error in %s", __func__);
248  va_end(list);
249  return false;
250  }
251 
252  if (!em->emcopy) {
253  em->emcopy = BKE_editmesh_copy(em);
254  }
255  em->emcopyusers++;
256 
257  BMO_op_exec(bm, &bmop);
258 
259  slot_select_out = BMO_slot_get(bmop.slots_out, select_slot_out);
260  hflag = slot_select_out->slot_subtype.elem & BM_ALL_NOLOOP;
261  BLI_assert(hflag != 0);
262 
263  if (select_extend == false) {
265  }
266 
268  em->bm, bmop.slots_out, select_slot_out, hflag, BM_ELEM_SELECT, true);
269 
270  va_end(list);
271  return EDBM_op_finish(em, &bmop, op, true);
272 }
273 
274 bool EDBM_op_call_silentf(BMEditMesh *em, const char *fmt, ...)
275 {
276  BMesh *bm = em->bm;
277  BMOperator bmop;
278  va_list list;
279 
280  va_start(list, fmt);
281 
282  if (!BMO_op_vinitf(bm, &bmop, BMO_FLAG_DEFAULTS, fmt, list)) {
283  va_end(list);
284  return false;
285  }
286 
287  if (!em->emcopy) {
288  em->emcopy = BKE_editmesh_copy(em);
289  }
290  em->emcopyusers++;
291 
292  BMO_op_exec(bm, &bmop);
293 
294  va_end(list);
295  return EDBM_op_finish(em, &bmop, NULL, false);
296 }
297 
300 /* -------------------------------------------------------------------- */
306 void EDBM_mesh_make(Object *ob, const int select_mode, const bool add_key_index)
307 {
308  Mesh *me = ob->data;
309  BMesh *bm;
310 
311  bm = BKE_mesh_to_bmesh(me,
312  ob,
313  add_key_index,
314  &((struct BMeshCreateParams){
315  .use_toolflags = true,
316  }));
317 
318  if (me->edit_mesh) {
319  /* this happens when switching shape keys */
321  MEM_freeN(me->edit_mesh);
322  }
323 
324  /* currently executing operators re-tessellates, so we can avoid doing here
325  * but at some point it may need to be added back. */
326 #if 0
327  me->edit_mesh = BKE_editmesh_create(bm, true);
328 #else
329  me->edit_mesh = BKE_editmesh_create(bm, false);
330 #endif
331 
332  me->edit_mesh->selectmode = me->edit_mesh->bm->selectmode = select_mode;
333  me->edit_mesh->mat_nr = (ob->actcol > 0) ? ob->actcol - 1 : 0;
334 
335  /* we need to flush selection because the mode may have changed from when last in editmode */
337 }
338 
343 void EDBM_mesh_load_ex(Main *bmain, Object *ob, bool free_data)
344 {
345  Mesh *me = ob->data;
346  BMesh *bm = me->edit_mesh->bm;
347 
348  /* Workaround for T42360, 'ob->shapenr' should be 1 in this case.
349  * however this isn't synchronized between objects at the moment. */
350  if (UNLIKELY((ob->shapenr == 0) && (me->key && !BLI_listbase_is_empty(&me->key->block)))) {
351  bm->shapenr = 1;
352  }
353 
354  BM_mesh_bm_to_me(bmain,
355  bm,
356  me,
357  (&(struct BMeshToMeshParams){
358  .calc_object_remap = true,
359  .update_shapekey_indices = !free_data,
360  }));
361 
362  /* Free derived mesh. usually this would happen through depsgraph but there
363  * are exceptions like file save that will not cause this, and we want to
364  * avoid ending up with an invalid derived mesh then.
365  *
366  * Do it for all objects which shares the same mesh datablock, since their
367  * derived meshes might also be referencing data which was just freed,
368  *
369  * Annoying enough, but currently seems most efficient way to avoid access
370  * of freed data on scene update, especially in cases when there are dependency
371  * cycles.
372  */
373 #if 0
374  for (Object *other_object = bmain->objects.first; other_object != NULL; other_object = other_object->id.next) {
375  if (other_object->data == ob->data) {
376  BKE_object_free_derived_caches(other_object);
377  }
378  }
379 #endif
380 }
381 
383 {
384  /* clear bmesh */
385  BM_mesh_clear(em->bm);
386 
387  /* free derived meshes */
389 
390  /* free tessellation data */
391  em->tottri = 0;
392  if (em->looptris) {
393  MEM_freeN(em->looptris);
394  em->looptris = NULL;
395  }
396 }
397 
398 void EDBM_mesh_load(Main *bmain, Object *ob)
399 {
400  EDBM_mesh_load_ex(bmain, ob, true);
401 }
402 
407 {
408  /* These tables aren't used yet, so it's not strictly necessary
409  * to 'end' them but if someone tries to start using them,
410  * having these in place will save a lot of pain. */
413 
414  BKE_editmesh_free(em);
415 }
416 
419 /* -------------------------------------------------------------------- */
424 {
426  Object *obedit = CTX_data_edit_object(C);
427  BMEditMesh *em = BKE_editmesh_from_object(obedit);
428 
429  if (!em) {
430  return;
431  }
432 
434 
435  /* Request redraw of header buttons (to show new select mode) */
437 }
438 
439 void EDBM_selectmode_flush_ex(BMEditMesh *em, const short selectmode)
440 {
441  BM_mesh_select_mode_flush_ex(em->bm, selectmode);
442 }
443 
445 {
447 }
448 
450 {
451  /* function below doesn't use. just do this to keep the values in sync */
452  em->bm->selectmode = em->selectmode;
454 }
455 
457 {
458  /* function below doesn't use. just do this to keep the values in sync */
459  em->bm->selectmode = em->selectmode;
461 }
462 
463 void EDBM_select_more(BMEditMesh *em, const bool use_face_step)
464 {
465  BMOperator bmop;
466  const bool use_faces = (em->selectmode == SCE_SELECT_FACE);
467 
468  BMO_op_initf(em->bm,
469  &bmop,
471  "region_extend geom=%hvef use_contract=%b use_faces=%b use_face_step=%b",
473  false,
474  use_faces,
475  use_face_step);
476  BMO_op_exec(em->bm, &bmop);
477  /* don't flush selection in edge/vertex mode */
479  em->bm, bmop.slots_out, "geom.out", BM_ALL_NOLOOP, BM_ELEM_SELECT, use_faces ? true : false);
480  BMO_op_finish(em->bm, &bmop);
481 
483 }
484 
485 void EDBM_select_less(BMEditMesh *em, const bool use_face_step)
486 {
487  BMOperator bmop;
488  const bool use_faces = (em->selectmode == SCE_SELECT_FACE);
489 
490  BMO_op_initf(em->bm,
491  &bmop,
493  "region_extend geom=%hvef use_contract=%b use_faces=%b use_face_step=%b",
495  true,
496  use_faces,
497  use_face_step);
498  BMO_op_exec(em->bm, &bmop);
499  /* don't flush selection in edge/vertex mode */
501  em->bm, bmop.slots_out, "geom.out", BM_ALL_NOLOOP, BM_ELEM_SELECT, use_faces ? true : false);
502  BMO_op_finish(em->bm, &bmop);
503 
505 
506  /* only needed for select less, ensure we don't have isolated elements remaining */
508 }
509 
510 void EDBM_flag_disable_all(BMEditMesh *em, const char hflag)
511 {
512  BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, hflag, false);
513 }
514 
515 void EDBM_flag_enable_all(BMEditMesh *em, const char hflag)
516 {
517  BM_mesh_elem_hflag_enable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, hflag, true);
518 }
519 
522 /* -------------------------------------------------------------------- */
529 UvVertMap *BM_uv_vert_map_create(BMesh *bm, const bool use_select, const bool use_winding)
530 {
531  BMVert *ev;
532  BMFace *efa;
533  BMLoop *l;
534  BMIter iter, liter;
535  /* vars from original func */
536  UvVertMap *vmap;
537  UvMapVert *buf;
538  const MLoopUV *luv;
539  uint a;
540  int totverts, i, totuv, totfaces;
541  const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
542  bool *winding = NULL;
544 
546 
547  totfaces = bm->totface;
548  totverts = bm->totvert;
549  totuv = 0;
550 
551  /* generate UvMapVert array */
552  BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
553  if ((use_select == false) || BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
554  totuv += efa->len;
555  }
556  }
557 
558  if (totuv == 0) {
559  return NULL;
560  }
561  vmap = (UvVertMap *)MEM_callocN(sizeof(*vmap), "UvVertMap");
562  if (!vmap) {
563  return NULL;
564  }
565 
566  vmap->vert = (UvMapVert **)MEM_callocN(sizeof(*vmap->vert) * totverts, "UvMapVert_pt");
567  buf = vmap->buf = (UvMapVert *)MEM_callocN(sizeof(*vmap->buf) * totuv, "UvMapVert");
568  if (use_winding) {
569  winding = MEM_callocN(sizeof(*winding) * totfaces, "winding");
570  }
571 
572  if (!vmap->vert || !vmap->buf) {
574  return NULL;
575  }
576 
577  BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, a) {
578  if ((use_select == false) || BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
579  float(*tf_uv)[2] = NULL;
580 
581  if (use_winding) {
582  tf_uv = (float(*)[2])BLI_buffer_reinit_data(&tf_uv_buf, vec2f, efa->len);
583  }
584 
585  BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
586  buf->loop_of_poly_index = i;
587  buf->poly_index = a;
588  buf->separate = 0;
589 
590  buf->next = vmap->vert[BM_elem_index_get(l->v)];
591  vmap->vert[BM_elem_index_get(l->v)] = buf;
592  buf++;
593 
594  if (use_winding) {
595  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
596  copy_v2_v2(tf_uv[i], luv->uv);
597  }
598  }
599 
600  if (use_winding) {
601  winding[a] = cross_poly_v2(tf_uv, efa->len) > 0;
602  }
603  }
604  }
605 
606  /* sort individual uvs for each vert */
607  BM_ITER_MESH_INDEX (ev, &iter, bm, BM_VERTS_OF_MESH, a) {
608  UvMapVert *newvlist = NULL, *vlist = vmap->vert[a];
609  UvMapVert *iterv, *v, *lastv, *next;
610  const float *uv, *uv2;
611 
612  while (vlist) {
613  v = vlist;
614  vlist = vlist->next;
615  v->next = newvlist;
616  newvlist = v;
617 
618  efa = BM_face_at_index(bm, v->poly_index);
619 
620  l = BM_iter_at_index(bm, BM_LOOPS_OF_FACE, efa, v->loop_of_poly_index);
621  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
622  uv = luv->uv;
623 
624  lastv = NULL;
625  iterv = vlist;
626 
627  while (iterv) {
628  next = iterv->next;
629  efa = BM_face_at_index(bm, iterv->poly_index);
631  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
632  uv2 = luv->uv;
633 
634  if (compare_v2v2(uv2, uv, STD_UV_CONNECT_LIMIT) &&
635  (!use_winding || winding[iterv->poly_index] == winding[v->poly_index])) {
636  if (lastv) {
637  lastv->next = next;
638  }
639  else {
640  vlist = next;
641  }
642  iterv->next = newvlist;
643  newvlist = iterv;
644  }
645  else {
646  lastv = iterv;
647  }
648 
649  iterv = next;
650  }
651 
652  newvlist->separate = 1;
653  }
654 
655  vmap->vert[a] = newvlist;
656  }
657 
658  if (use_winding) {
659  MEM_freeN(winding);
660  }
661 
662  BLI_buffer_free(&tf_uv_buf);
663 
664  return vmap;
665 }
666 
668 {
669  return vmap->vert[v];
670 }
671 
672 /* A specialized vert map used by stitch operator */
674  const Scene *scene,
675  const bool face_selected,
676  const bool uv_selected,
677  const bool use_winding,
678  const bool do_islands)
679 {
680  BMVert *ev;
681  BMFace *efa;
682  BMLoop *l;
683  BMIter iter, liter;
684  /* vars from original func */
685  UvElementMap *element_map;
686  UvElement *buf;
687  bool *winding = NULL;
689 
690  MLoopUV *luv;
691  int totverts, totfaces, i, totuv, j;
692 
693  const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
694 
696 
697  totfaces = bm->totface;
698  totverts = bm->totvert;
699  totuv = 0;
700 
701  /* generate UvElement array */
702  BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
703  if (!face_selected || BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
704  if (!uv_selected) {
705  totuv += efa->len;
706  }
707  else {
708  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
709  if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
710  totuv++;
711  }
712  }
713  }
714  }
715  }
716 
717  if (totuv == 0) {
718  return NULL;
719  }
720 
721  element_map = (UvElementMap *)MEM_callocN(sizeof(*element_map), "UvElementMap");
722  element_map->totalUVs = totuv;
723  element_map->vert = (UvElement **)MEM_callocN(sizeof(*element_map->vert) * totverts,
724  "UvElementVerts");
725  buf = element_map->buf = (UvElement *)MEM_callocN(sizeof(*element_map->buf) * totuv,
726  "UvElement");
727 
728  if (use_winding) {
729  winding = MEM_mallocN(sizeof(*winding) * totfaces, "winding");
730  }
731 
732  BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, j) {
733 
734  if (use_winding) {
735  winding[j] = false;
736  }
737 
738  if (!face_selected || BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
739  float(*tf_uv)[2] = NULL;
740 
741  if (use_winding) {
742  tf_uv = (float(*)[2])BLI_buffer_reinit_data(&tf_uv_buf, vec2f, efa->len);
743  }
744 
745  BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
746  if (uv_selected && !uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
747  continue;
748  }
749 
750  buf->l = l;
751  buf->separate = 0;
752  buf->island = INVALID_ISLAND;
753  buf->loop_of_poly_index = i;
754 
755  buf->next = element_map->vert[BM_elem_index_get(l->v)];
756  element_map->vert[BM_elem_index_get(l->v)] = buf;
757 
758  if (use_winding) {
759  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
760  copy_v2_v2(tf_uv[i], luv->uv);
761  }
762 
763  buf++;
764  }
765 
766  if (use_winding) {
767  winding[j] = cross_poly_v2(tf_uv, efa->len) > 0;
768  }
769  }
770  }
771 
772  /* sort individual uvs for each vert */
773  BM_ITER_MESH_INDEX (ev, &iter, bm, BM_VERTS_OF_MESH, i) {
774  UvElement *newvlist = NULL, *vlist = element_map->vert[i];
775  UvElement *iterv, *v, *lastv, *next;
776  const float *uv, *uv2;
777  bool uv_vert_sel, uv2_vert_sel;
778 
779  while (vlist) {
780  v = vlist;
781  vlist = vlist->next;
782  v->next = newvlist;
783  newvlist = v;
784 
785  l = v->l;
786  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
787  uv = luv->uv;
788  uv_vert_sel = uvedit_uv_select_test(scene, l, cd_loop_uv_offset);
789 
790  lastv = NULL;
791  iterv = vlist;
792 
793  while (iterv) {
794  next = iterv->next;
795 
796  l = iterv->l;
797  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
798  uv2 = luv->uv;
799  uv2_vert_sel = uvedit_uv_select_test(scene, l, cd_loop_uv_offset);
800 
801  /* Check if the uv loops share the same selection state (if not, they are not connected as
802  * they have been ripped or other edit commands have separated them). */
803  const bool connected = (uv_vert_sel == uv2_vert_sel) &&
805 
806  if (connected && (!use_winding || winding[BM_elem_index_get(iterv->l->f)] ==
807  winding[BM_elem_index_get(v->l->f)])) {
808  if (lastv) {
809  lastv->next = next;
810  }
811  else {
812  vlist = next;
813  }
814  iterv->next = newvlist;
815  newvlist = iterv;
816  }
817  else {
818  lastv = iterv;
819  }
820 
821  iterv = next;
822  }
823 
824  newvlist->separate = 1;
825  }
826 
827  element_map->vert[i] = newvlist;
828  }
829 
830  if (use_winding) {
831  MEM_freeN(winding);
832  }
833 
834  if (do_islands) {
835  uint *map;
836  BMFace **stack;
837  int stacksize = 0;
838  UvElement *islandbuf;
839  /* island number for faces */
840  int *island_number = NULL;
841 
842  int nislands = 0, islandbufsize = 0;
843 
844  /* map holds the map from current vmap->buf to the new, sorted map */
845  map = MEM_mallocN(sizeof(*map) * totuv, "uvelement_remap");
846  stack = MEM_mallocN(sizeof(*stack) * bm->totface, "uv_island_face_stack");
847  islandbuf = MEM_callocN(sizeof(*islandbuf) * totuv, "uvelement_island_buffer");
848  island_number = MEM_mallocN(sizeof(*island_number) * totfaces, "uv_island_number_face");
849  copy_vn_i(island_number, totfaces, INVALID_ISLAND);
850 
851  /* at this point, every UvElement in vert points to a UvElement sharing the same vertex.
852  * Now we should sort uv's in islands. */
853  for (i = 0; i < totuv; i++) {
854  if (element_map->buf[i].island == INVALID_ISLAND) {
855  element_map->buf[i].island = nislands;
856  stack[0] = element_map->buf[i].l->f;
857  island_number[BM_elem_index_get(stack[0])] = nislands;
858  stacksize = 1;
859 
860  while (stacksize > 0) {
861  efa = stack[--stacksize];
862 
863  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
864  if (uv_selected && !uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
865  continue;
866  }
867 
868  UvElement *element, *initelement = element_map->vert[BM_elem_index_get(l->v)];
869 
870  for (element = initelement; element; element = element->next) {
871  if (element->separate) {
872  initelement = element;
873  }
874 
875  if (element->l->f == efa) {
876  /* found the uv corresponding to our face and vertex.
877  * Now fill it to the buffer */
878  element->island = nislands;
879  map[element - element_map->buf] = islandbufsize;
880  islandbuf[islandbufsize].l = element->l;
881  islandbuf[islandbufsize].separate = element->separate;
882  islandbuf[islandbufsize].loop_of_poly_index = element->loop_of_poly_index;
883  islandbuf[islandbufsize].island = nislands;
884  islandbufsize++;
885 
886  for (element = initelement; element; element = element->next) {
887  if (element->separate && element != initelement) {
888  break;
889  }
890 
891  if (island_number[BM_elem_index_get(element->l->f)] == INVALID_ISLAND) {
892  stack[stacksize++] = element->l->f;
893  island_number[BM_elem_index_get(element->l->f)] = nislands;
894  }
895  }
896  break;
897  }
898  }
899  }
900  }
901 
902  nislands++;
903  }
904  }
905 
906  MEM_freeN(island_number);
907 
908  /* remap */
909  for (i = 0; i < bm->totvert; i++) {
910  /* important since we may do selection only. Some of these may be NULL */
911  if (element_map->vert[i]) {
912  element_map->vert[i] = &islandbuf[map[element_map->vert[i] - element_map->buf]];
913  }
914  }
915 
916  element_map->islandIndices = MEM_callocN(sizeof(*element_map->islandIndices) * nislands,
917  "UvElementMap_island_indices");
918  j = 0;
919  for (i = 0; i < totuv; i++) {
920  UvElement *element = element_map->buf[i].next;
921  if (element == NULL) {
922  islandbuf[map[i]].next = NULL;
923  }
924  else {
925  islandbuf[map[i]].next = &islandbuf[map[element - element_map->buf]];
926  }
927 
928  if (islandbuf[i].island != j) {
929  j++;
930  element_map->islandIndices[j] = i;
931  }
932  }
933 
934  MEM_freeN(element_map->buf);
935 
936  element_map->buf = islandbuf;
937  element_map->totalIslands = nislands;
938  MEM_freeN(stack);
939  MEM_freeN(map);
940  }
941 
942  BLI_buffer_free(&tf_uv_buf);
943 
944  return element_map;
945 }
946 
948 {
949  if (vmap) {
950  if (vmap->vert) {
951  MEM_freeN(vmap->vert);
952  }
953  if (vmap->buf) {
954  MEM_freeN(vmap->buf);
955  }
956  MEM_freeN(vmap);
957  }
958 }
959 
961 {
962  if (element_map) {
963  if (element_map->vert) {
964  MEM_freeN(element_map->vert);
965  }
966  if (element_map->buf) {
967  MEM_freeN(element_map->buf);
968  }
969  if (element_map->islandIndices) {
970  MEM_freeN(element_map->islandIndices);
971  }
972  MEM_freeN(element_map);
973  }
974 }
975 
977 {
978  for (UvElement *element = map->vert[BM_elem_index_get(l->v)]; element; element = element->next) {
979  if (element->l->f == efa) {
980  return element;
981  }
982  }
983 
984  return NULL;
985 }
986 
989 /* -------------------------------------------------------------------- */
997 BMFace *EDBM_uv_active_face_get(BMEditMesh *em, const bool sloppy, const bool selected)
998 {
999  BMFace *efa = NULL;
1000 
1001  if (!EDBM_uv_check(em)) {
1002  return NULL;
1003  }
1004 
1005  efa = BM_mesh_active_face_get(em->bm, sloppy, selected);
1006 
1007  if (efa) {
1008  return efa;
1009  }
1010 
1011  return NULL;
1012 }
1013 
1014 /* can we edit UV's for this mesh?*/
1016 {
1017  /* some of these checks could be a touch overkill */
1018  return em && em->bm->totface && CustomData_has_layer(&em->bm->ldata, CD_MLOOPUV);
1019 }
1020 
1022 {
1023  /* some of these checks could be a touch overkill */
1024  return em && em->bm->totface && CustomData_has_layer(&em->bm->ldata, CD_MLOOPCOL);
1025 }
1026 
1029 /* -------------------------------------------------------------------- */
1033 static BMVert *cache_mirr_intptr_as_bmvert(const intptr_t *index_lookup, int index)
1034 {
1035  intptr_t eve_i = index_lookup[index];
1036  return (eve_i == -1) ? NULL : (BMVert *)eve_i;
1037 }
1038 
1055 /* BM_SEARCH_MAXDIST is too big, copied from 2.6x MOC_THRESH, should become a
1056  * preference */
1057 #define BM_SEARCH_MAXDIST_MIRR 0.00002f
1058 #define BM_CD_LAYER_ID "__mirror_index"
1070  const int axis,
1071  const bool use_self,
1072  const bool use_select,
1073  const bool respecthide,
1074  /* extra args */
1075  const bool use_topology,
1076  float maxdist,
1077  int *r_index)
1078 {
1079  BMesh *bm = em->bm;
1080  BMIter iter;
1081  BMVert *v;
1082  int cd_vmirr_offset = 0;
1083  int i;
1084  const float maxdist_sq = square_f(maxdist);
1085 
1086  /* one or the other is used depending if topo is enabled */
1087  KDTree_3d *tree = NULL;
1088  MirrTopoStore_t mesh_topo_store = {NULL, -1, -1, -1};
1089 
1091 
1092  if (r_index == NULL) {
1093  const char *layer_id = BM_CD_LAYER_ID;
1095  if (em->mirror_cdlayer == -1) {
1098  }
1099 
1100  cd_vmirr_offset = CustomData_get_n_offset(
1101  &bm->vdata,
1102  CD_PROP_INT32,
1104 
1106  }
1107 
1109 
1110  if (use_topology) {
1112  }
1113  else {
1114  tree = BLI_kdtree_3d_new(bm->totvert);
1115  BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
1116  if (respecthide && BM_elem_flag_test(v, BM_ELEM_HIDDEN)) {
1117  continue;
1118  }
1119 
1120  BLI_kdtree_3d_insert(tree, i, v->co);
1121  }
1122  BLI_kdtree_3d_balance(tree);
1123  }
1124 
1125 #define VERT_INTPTR(_v, _i) (r_index ? &r_index[_i] : BM_ELEM_CD_GET_VOID_P(_v, cd_vmirr_offset))
1126 
1127  BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
1128  if (respecthide && BM_elem_flag_test(v, BM_ELEM_HIDDEN)) {
1129  continue;
1130  }
1131 
1132  if (use_select && !BM_elem_flag_test(v, BM_ELEM_SELECT)) {
1133  continue;
1134  }
1135 
1137  BMVert *v_mirr;
1138  int *idx = VERT_INTPTR(v, i);
1139 
1140  if (use_topology) {
1142  if (v_mirr != NULL) {
1143  if (respecthide && BM_elem_flag_test(v_mirr, BM_ELEM_HIDDEN)) {
1144  v_mirr = NULL;
1145  }
1146  }
1147  }
1148  else {
1149  int i_mirr;
1150  float co[3];
1151  copy_v3_v3(co, v->co);
1152  co[axis] *= -1.0f;
1153 
1154  v_mirr = NULL;
1155  i_mirr = BLI_kdtree_3d_find_nearest(tree, co, NULL);
1156  if (i_mirr != -1) {
1157  BMVert *v_test = BM_vert_at_index(bm, i_mirr);
1158  if (len_squared_v3v3(co, v_test->co) < maxdist_sq) {
1159  v_mirr = v_test;
1160  }
1161  }
1162  }
1163 
1164  if (v_mirr && (use_self || (v_mirr != v))) {
1165  const int i_mirr = BM_elem_index_get(v_mirr);
1166  *idx = i_mirr;
1167  idx = VERT_INTPTR(v_mirr, i_mirr);
1168  *idx = i;
1169  }
1170  else {
1171  *idx = -1;
1172  }
1173  }
1174 
1175 #undef VERT_INTPTR
1176 
1177  if (use_topology) {
1179  }
1180  else {
1181  BLI_kdtree_3d_free(tree);
1182  }
1183 }
1184 
1186  const int axis,
1187  const bool use_self,
1188  const bool use_select,
1189  const bool respecthide,
1190  const bool use_topology)
1191 {
1193  axis,
1194  use_self,
1195  use_select,
1196  respecthide,
1197  /* extra args */
1198  use_topology,
1200  NULL);
1201 }
1202 
1204 {
1205  const int *mirr = CustomData_bmesh_get_layer_n(&em->bm->vdata, v->head.data, em->mirror_cdlayer);
1206 
1207  BLI_assert(em->mirror_cdlayer != -1); /* invalid use */
1208 
1209  if (mirr && *mirr >= 0 && *mirr < em->bm->totvert) {
1210  if (!em->bm->vtable) {
1211  printf(
1212  "err: should only be called between "
1213  "EDBM_verts_mirror_cache_begin and EDBM_verts_mirror_cache_end");
1214  return NULL;
1215  }
1216 
1217  return em->bm->vtable[*mirr];
1218  }
1219 
1220  return NULL;
1221 }
1222 
1224 {
1225  BMVert *v1_mirr = EDBM_verts_mirror_get(em, e->v1);
1226  if (v1_mirr) {
1227  BMVert *v2_mirr = EDBM_verts_mirror_get(em, e->v2);
1228  if (v2_mirr) {
1229  return BM_edge_exists(v1_mirr, v2_mirr);
1230  }
1231  }
1232 
1233  return NULL;
1234 }
1235 
1237 {
1238  BMVert **v_mirr_arr = BLI_array_alloca(v_mirr_arr, f->len);
1239 
1240  BMLoop *l_iter, *l_first;
1241  uint i = 0;
1242 
1243  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
1244  do {
1245  if ((v_mirr_arr[i++] = EDBM_verts_mirror_get(em, l_iter->v)) == NULL) {
1246  return NULL;
1247  }
1248  } while ((l_iter = l_iter->next) != l_first);
1249 
1250  return BM_face_exists(v_mirr_arr, f->len);
1251 }
1252 
1254 {
1255  int *mirr = CustomData_bmesh_get_layer_n(&em->bm->vdata, v->head.data, em->mirror_cdlayer);
1256 
1257  BLI_assert(em->mirror_cdlayer != -1); /* invalid use */
1258 
1259  if (mirr) {
1260  *mirr = -1;
1261  }
1262 }
1263 
1265 {
1266  em->mirror_cdlayer = -1;
1267 }
1268 
1269 void EDBM_verts_mirror_apply(BMEditMesh *em, const int sel_from, const int sel_to)
1270 {
1271  BMIter iter;
1272  BMVert *v;
1273 
1274  BLI_assert((em->bm->vtable != NULL) && ((em->bm->elem_table_dirty & BM_VERT) == 0));
1275 
1276  BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
1277  if (BM_elem_flag_test(v, BM_ELEM_SELECT) == sel_from) {
1278  BMVert *mirr = EDBM_verts_mirror_get(em, v);
1279  if (mirr) {
1280  if (BM_elem_flag_test(mirr, BM_ELEM_SELECT) == sel_to) {
1281  copy_v3_v3(mirr->co, v->co);
1282  mirr->co[0] *= -1.0f;
1283  }
1284  }
1285  }
1286  }
1287 }
1288 
1291 /* -------------------------------------------------------------------- */
1295 /* swap is 0 or 1, if 1 it hides not selected */
1297 {
1298  BMIter iter;
1299  BMElem *ele;
1300  int itermode;
1301  char hflag_swap = swap ? BM_ELEM_SELECT : 0;
1302  bool changed = true;
1303 
1304  if (em->selectmode & SCE_SELECT_VERTEX) {
1305  itermode = BM_VERTS_OF_MESH;
1306  }
1307  else if (em->selectmode & SCE_SELECT_EDGE) {
1308  itermode = BM_EDGES_OF_MESH;
1309  }
1310  else {
1311  itermode = BM_FACES_OF_MESH;
1312  }
1313 
1314  BM_ITER_MESH (ele, &iter, em->bm, itermode) {
1315  if (!BM_elem_flag_test(ele, BM_ELEM_HIDDEN)) {
1316  if (BM_elem_flag_test(ele, BM_ELEM_SELECT) ^ hflag_swap) {
1317  BM_elem_hide_set(em->bm, ele, true);
1318  changed = true;
1319  }
1320  }
1321  }
1322 
1323  if (changed) {
1325  }
1326  return changed;
1327 
1328  /* original hide flushing comment (OUTDATED):
1329  * hide happens on least dominant select mode, and flushes up, not down!
1330  * (helps preventing errors in subsurf) */
1331  /* - vertex hidden, always means edge is hidden too
1332  * - edge hidden, always means face is hidden too
1333  * - face hidden, only set face hide
1334  * - then only flush back down what's absolute hidden
1335  */
1336 }
1337 
1339 {
1340  const char iter_types[3] = {
1344  };
1345 
1346  const bool sels[3] = {
1347  (em->selectmode & SCE_SELECT_VERTEX) != 0,
1348  (em->selectmode & SCE_SELECT_EDGE) != 0,
1349  (em->selectmode & SCE_SELECT_FACE) != 0,
1350  };
1351  int i;
1352  bool changed = false;
1353 
1354  /* Use tag flag to remember what was hidden before all is revealed.
1355  * BM_ELEM_HIDDEN --> BM_ELEM_TAG */
1356  for (i = 0; i < 3; i++) {
1357  BMIter iter;
1358  BMElem *ele;
1359 
1360  BM_ITER_MESH (ele, &iter, em->bm, iter_types[i]) {
1361  if (BM_elem_flag_test(ele, BM_ELEM_HIDDEN)) {
1363  changed = true;
1364  }
1365  else {
1367  }
1368  }
1369  }
1370 
1371  if (!changed) {
1372  return false;
1373  }
1374 
1375  /* Reveal everything */
1377 
1378  /* Select relevant just-revealed elements */
1379  for (i = 0; i < 3; i++) {
1380  BMIter iter;
1381  BMElem *ele;
1382 
1383  if (!sels[i]) {
1384  continue;
1385  }
1386 
1387  BM_ITER_MESH (ele, &iter, em->bm, iter_types[i]) {
1388  if (BM_elem_flag_test(ele, BM_ELEM_TAG)) {
1389  BM_elem_select_set(em->bm, ele, select);
1390  }
1391  }
1392  }
1393 
1395 
1396  /* hidden faces can have invalid normals */
1398 
1399  return true;
1400 }
1401 
1404 /* -------------------------------------------------------------------- */
1409 {
1411 }
1412 
1414 {
1415  const char iter_types[3] = {
1419  };
1420 
1421  BMIter iter;
1422  BMElem *ele;
1423  int *tots[3];
1424  int i;
1425 
1426  tots[0] = &em->bm->totvertsel;
1427  tots[1] = &em->bm->totedgesel;
1428  tots[2] = &em->bm->totfacesel;
1429 
1430  em->bm->totvertsel = em->bm->totedgesel = em->bm->totfacesel = 0;
1431 
1432  for (i = 0; i < 3; i++) {
1433  ele = BM_iter_new(&iter, em->bm, iter_types[i], NULL);
1434  for (; ele; ele = BM_iter_step(&iter)) {
1435  if (BM_elem_flag_test(ele, BM_ELEM_SELECT)) {
1436  (*tots[i])++;
1437  }
1438  }
1439  }
1440 }
1441 
1442 /* so many tools call these that we better make it a generic function.
1443  */
1444 void EDBM_update_generic(Mesh *mesh, const bool do_tessellation, const bool is_destructive)
1445 {
1446  BMEditMesh *em = mesh->edit_mesh;
1447  /* Order of calling isn't important. */
1450 
1451  if (do_tessellation) {
1453  }
1454 
1455  if (is_destructive) {
1456  /* TODO. we may be able to remove this now! - Campbell */
1457  // BM_mesh_elem_table_free(em->bm, BM_ALL_NOLOOP);
1458  }
1459  else {
1460  /* in debug mode double check we didn't need to recalculate */
1461  BLI_assert(BM_mesh_elem_table_check(em->bm) == true);
1462  }
1463  if (em->bm->spacearr_dirty & BM_SPACEARR_BMO_SET) {
1464  BM_lnorspace_invalidate(em->bm, false);
1466  }
1467  /* don't keep stale derivedMesh data around, see: T38872. */
1469 
1470 #ifdef DEBUG
1471  {
1472  BMEditSelection *ese;
1473  for (ese = em->bm->selected.first; ese; ese = ese->next) {
1475  }
1476  }
1477 #endif
1478 }
1479 
1482 /* -------------------------------------------------------------------- */
1486 /* poll call for mesh operators requiring a view3d context */
1488 {
1490  return 1;
1491  }
1492 
1493  return 0;
1494 }
1495 
1498 /* -------------------------------------------------------------------- */
1503 {
1504  BMElem *ele = NULL;
1505 
1506  if ((em->selectmode & SCE_SELECT_VERTEX) && eve) {
1507  ele = (BMElem *)eve;
1508  }
1509  else if ((em->selectmode & SCE_SELECT_EDGE) && eed) {
1510  ele = (BMElem *)eed;
1511  }
1512  else if ((em->selectmode & SCE_SELECT_FACE) && efa) {
1513  ele = (BMElem *)efa;
1514  }
1515 
1516  return ele;
1517 }
1518 
1525 {
1526  BMesh *bm = em->bm;
1527  int index = BM_elem_index_get(ele);
1528 
1529  if (ele->head.htype == BM_VERT) {
1531  }
1532  else if (ele->head.htype == BM_EDGE) {
1534  index += bm->totvert;
1535  }
1536  else if (ele->head.htype == BM_FACE) {
1538  index += bm->totvert + bm->totedge;
1539  }
1540  else {
1541  BLI_assert(0);
1542  }
1543 
1544  return index;
1545 }
1546 
1548 {
1549  BMesh *bm = em->bm;
1550 
1551  if (index < bm->totvert) {
1552  return (BMElem *)BM_vert_at_index_find_or_table(bm, index);
1553  }
1554  index -= bm->totvert;
1555  if (index < bm->totedge) {
1556  return (BMElem *)BM_edge_at_index_find_or_table(bm, index);
1557  }
1558  index -= bm->totedge;
1559  if (index < bm->totface) {
1560  return (BMElem *)BM_face_at_index_find_or_table(bm, index);
1561  }
1562 
1563  return NULL;
1564 }
1565 
1567  BMEditMesh *em,
1568  BMElem *ele,
1569  int *r_object_index)
1570 {
1571  uint bases_len;
1572  int elem_index = -1;
1573  *r_object_index = -1;
1574  Base **bases = BKE_view_layer_array_from_bases_in_edit_mode(view_layer, NULL, &bases_len);
1575  for (uint base_index = 0; base_index < bases_len; base_index++) {
1576  Base *base_iter = bases[base_index];
1577  if (BKE_editmesh_from_object(base_iter->object) == em) {
1578  *r_object_index = base_index;
1579  elem_index = EDBM_elem_to_index_any(em, ele);
1580  break;
1581  }
1582  }
1583  MEM_freeN(bases);
1584  return elem_index;
1585 }
1586 
1588  int object_index,
1589  int elem_index,
1590  Object **r_obedit)
1591 {
1592  uint bases_len;
1593  Base **bases = BKE_view_layer_array_from_bases_in_edit_mode(view_layer, NULL, &bases_len);
1594  *r_obedit = NULL;
1595  Object *obedit = ((uint)object_index < bases_len) ? bases[object_index]->object : NULL;
1596  MEM_freeN(bases);
1597  if (obedit != NULL) {
1598  BMEditMesh *em = BKE_editmesh_from_object(obedit);
1599  BMElem *ele = EDBM_elem_from_index_any(em, elem_index);
1600  if (ele != NULL) {
1601  *r_obedit = obedit;
1602  return ele;
1603  }
1604  }
1605  return NULL;
1606 }
1607 
1610 /* -------------------------------------------------------------------- */
1615  struct BMBVHTree *tree, const float co[3], const float dir[3], float *r_hitout, BMEdge *e)
1616 {
1617  BMFace *f = BKE_bmbvh_ray_cast(tree, co, dir, 0.0f, NULL, r_hitout, NULL);
1618 
1619  if (f && BM_edge_in_face(e, f)) {
1620  return NULL;
1621  }
1622 
1623  return f;
1624 }
1625 
1626 static void scale_point(float c1[3], const float p[3], const float s)
1627 {
1628  sub_v3_v3(c1, p);
1629  mul_v3_fl(c1, s);
1630  add_v3_v3(c1, p);
1631 }
1632 
1634  BMEdge *e,
1635  struct Depsgraph *depsgraph,
1636  ARegion *region,
1637  View3D *v3d,
1638  Object *obedit)
1639 {
1640  BMFace *f;
1641  float co1[3], co2[3], co3[3], dir1[3], dir2[3], dir3[3];
1642  float origin[3], invmat[4][4];
1643  float epsilon = 0.01f;
1644  float end[3];
1645  const float mval_f[2] = {
1646  region->winx / 2.0f,
1647  region->winy / 2.0f,
1648  };
1649 
1650  ED_view3d_win_to_segment_clipped(depsgraph, region, v3d, mval_f, origin, end, false);
1651 
1652  invert_m4_m4(invmat, obedit->obmat);
1653  mul_m4_v3(invmat, origin);
1654 
1655  copy_v3_v3(co1, e->v1->co);
1656  mid_v3_v3v3(co2, e->v1->co, e->v2->co);
1657  copy_v3_v3(co3, e->v2->co);
1658 
1659  scale_point(co1, co2, 0.99);
1660  scale_point(co3, co2, 0.99);
1661 
1662  /* ok, idea is to generate rays going from the camera origin to the
1663  * three points on the edge (v1, mid, v2)*/
1664  sub_v3_v3v3(dir1, origin, co1);
1665  sub_v3_v3v3(dir2, origin, co2);
1666  sub_v3_v3v3(dir3, origin, co3);
1667 
1671 
1672  /* offset coordinates slightly along view vectors, to avoid
1673  * hitting the faces that own the edge.*/
1674  add_v3_v3v3(co1, co1, dir1);
1675  add_v3_v3v3(co2, co2, dir2);
1676  add_v3_v3v3(co3, co3, dir3);
1677 
1678  normalize_v3(dir1);
1679  normalize_v3(dir2);
1680  normalize_v3(dir3);
1681 
1682  /* do three samplings: left, middle, right */
1683  f = edge_ray_cast(tree, co1, dir1, NULL, e);
1684  if (f && !edge_ray_cast(tree, co2, dir2, NULL, e)) {
1685  return true;
1686  }
1687  if (f && !edge_ray_cast(tree, co3, dir3, NULL, e)) {
1688  return true;
1689  }
1690  if (!f) {
1691  return true;
1692  }
1693 
1694  return false;
1695 }
1696 
1699 /* -------------------------------------------------------------------- */
1704  bContext *C, Depsgraph *depsgraph, ARegion *region, Object *obedit, BMEditMesh *em)
1705 {
1706  BMIter iter;
1707  BMVert *eve;
1708 
1709  ED_view3d_init_mats_rv3d(obedit, region->regiondata);
1710 
1713 
1714  BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
1715  if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
1716  float mval[2], co_proj[3];
1718  V3D_PROJ_RET_OK) {
1719  if (ED_transform_snap_object_project_view3d(snap_context,
1720  depsgraph,
1722  &(const struct SnapObjectParams){
1723  .snap_select = SNAP_NOT_ACTIVE,
1724  .use_object_edit_cage = false,
1725  .use_occlusion_test = true,
1726  },
1727  mval,
1728  NULL,
1729  NULL,
1730  co_proj,
1731  NULL)) {
1732  mul_v3_m4v3(eve->co, obedit->imat, co_proj);
1733  }
1734  }
1735  }
1736  }
1737 
1739 }
1740 
typedef float(TangentPoint)[2]
struct Scene * CTX_data_scene(const bContext *C)
Definition: context.c:1034
struct Object * CTX_data_edit_object(const bContext *C)
Definition: context.c:1296
struct View3D * CTX_wm_view3d(const bContext *C)
Definition: context.c:760
bool CustomData_has_layer(const struct CustomData *data, int type)
int CustomData_get_named_layer_index(const struct CustomData *data, int type, const char *name)
int CustomData_get_layer_index(const struct CustomData *data, int type)
void * CustomData_bmesh_get_layer_n(const struct CustomData *data, void *block, int n)
int CustomData_get_n_offset(const struct CustomData *data, int type, int n)
int CustomData_get_offset(const struct CustomData *data, int type)
void BKE_editmesh_free_derivedmesh(BMEditMesh *em)
Definition: editmesh.c:151
void BKE_editmesh_looptri_calc(BMEditMesh *em)
Definition: editmesh.c:135
BMEditMesh * BKE_editmesh_from_object(struct Object *ob)
Return the BMEditMesh for a given object.
Definition: editmesh.c:85
void BKE_editmesh_free(BMEditMesh *em)
Definition: editmesh.c:165
BMEditMesh * BKE_editmesh_copy(BMEditMesh *em)
Definition: editmesh.c:54
BMEditMesh * BKE_editmesh_create(BMesh *bm, const bool do_tessellate)
Definition: editmesh.c:42
struct BMFace * BKE_bmbvh_ray_cast(BMBVHTree *tree, const float co[3], const float dir[3], const float radius, float *r_dist, float r_hitout[3], float r_cagehit[3])
Definition: editmesh_bvh.c:306
#define G_MAIN
Definition: BKE_global.h:232
#define BKE_view_layer_array_from_bases_in_edit_mode(view_layer, v3d, r_len)
Definition: BKE_layer.h:423
struct BMesh * BKE_mesh_to_bmesh(struct Mesh *me, struct Object *ob, const bool add_key_index, const struct BMeshCreateParams *params)
Definition: mesh.c:1019
#define INVALID_ISLAND
void BKE_mesh_uv_vert_map_free(UvVertMap *vmap)
Definition: mesh_mapping.c:184
#define STD_UV_CONNECT_LIMIT
General operations, lookup, etc. for blender objects.
void BKE_object_free_derived_caches(struct Object *ob)
Definition: object.c:1719
void BKE_report(ReportList *reports, ReportType type, const char *message)
Definition: report.c:104
void BKE_reportf(ReportList *reports, ReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
#define BLI_array_alloca(arr, realsize)
Definition: BLI_alloca.h:36
#define BLI_assert(a)
Definition: BLI_assert.h:58
#define BLI_buffer_reinit_data(buffer_, type_, new_count_)
Definition: BLI_buffer.h:61
@ BLI_BUFFER_NOP
Definition: BLI_buffer.h:35
#define BLI_buffer_declare_static(type_, name_, flag_, static_count_)
Definition: BLI_buffer.h:39
#define BLI_buffer_free(name_)
Definition: BLI_buffer.h:92
A kd-tree for nearest neighbor search.
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
Definition: BLI_listbase.h:124
MINLINE float square_f(float a)
float cross_poly_v2(const float verts[][2], unsigned int nr)
Definition: math_geom.c:171
bool invert_m4_m4(float R[4][4], const float A[4][4])
Definition: math_matrix.c:1278
void mul_m4_v3(const float M[4][4], float r[3])
Definition: math_matrix.c:732
void mul_v3_m4v3(float r[3], const float M[4][4], const float v[3])
Definition: math_matrix.c:742
void copy_vn_i(int *array_tar, const int size, const int val)
Definition: math_vector.c:1374
MINLINE float normalize_v3(float r[3])
MINLINE void sub_v3_v3(float r[3], const float a[3])
MINLINE float len_squared_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void sub_v3_v3v3(float r[3], const float a[3], const float b[3])
MINLINE bool compare_v2v2(const float a[2], const float b[2], const float limit) ATTR_WARN_UNUSED_RESULT
MINLINE void copy_v2_v2(float r[2], const float a[2])
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE void copy_v3_v3(float r[3], const float a[3])
MINLINE void add_v3_v3v3(float r[3], const float a[3], const float b[3])
void mid_v3_v3v3(float r[3], const float a[3], const float b[3])
Definition: math_vector.c:270
MINLINE float normalize_v3_length(float r[3], const float unit_scale)
MINLINE void add_v3_v3(float r[3], const float a[3])
unsigned int uint
Definition: BLI_sys_types.h:83
#define UNLIKELY(x)
void swap(T &a, T &b)
Definition: Common.h:33
struct Depsgraph Depsgraph
Definition: DEG_depsgraph.h:51
void DEG_id_tag_update(struct ID *id, int flag)
@ ID_RECALC_COPY_ON_WRITE
Definition: DNA_ID.h:654
@ ID_RECALC_GEOMETRY
Definition: DNA_ID.h:611
@ CD_PROP_INT32
@ CD_MLOOPCOL
@ CD_MLOOPUV
@ CD_FLAG_TEMPORARY
Object is a sort of wrapper for general info.
#define SCE_SNAP_MODE_FACE
#define SCE_SELECT_FACE
#define SCE_SELECT_VERTEX
#define SCE_SELECT_EDGE
void ED_mesh_mirror_topo_table_end(struct Object *ob)
void ED_mesh_mirrtopo_init(struct BMEditMesh *em, struct Mesh *me, MirrTopoStore_t *mesh_topo_store, const bool skip_em_vert_array_init)
void ED_mesh_mirrtopo_free(MirrTopoStore_t *mesh_topo_store)
void ED_mesh_mirror_spatial_table_end(struct Object *ob)
bool ED_operator_view3d_active(struct bContext *C)
Definition: screen_ops.c:230
bool ED_operator_editmesh(struct bContext *C)
Definition: screen_ops.c:404
SnapObjectContext * ED_transform_snap_object_context_create_view3d(struct Scene *scene, int flag, const struct ARegion *region, const struct View3D *v3d)
bool ED_transform_snap_object_project_view3d(struct SnapObjectContext *sctx, struct Depsgraph *depsgraph, const unsigned short snap_to, const struct SnapObjectParams *params, const float mval[2], const float prev_co[3], float *dist_px, float r_loc[3], float r_no[3])
void ED_transform_snap_object_context_destroy(SnapObjectContext *sctx)
bool uvedit_uv_select_test(const struct Scene *scene, struct BMLoop *l, const int cd_loop_uv_offset)
bool ED_view3d_win_to_segment_clipped(struct Depsgraph *depsgraph, const struct ARegion *region, struct View3D *v3d, const float mval[2], float r_ray_start[3], float r_ray_end[3], const bool do_clip)
void ED_view3d_init_mats_rv3d(struct Object *ob, struct RegionView3D *rv3d)
Definition: space_view3d.c:190
@ V3D_PROJ_TEST_NOP
Definition: ED_view3d.h:193
eV3DProjStatus ED_view3d_project_float_object(const struct ARegion *region, const float co[3], float r_co[2], const eV3DProjTest flag)
@ V3D_PROJ_RET_OK
Definition: ED_view3d.h:176
Read Guarded memory(de)allocation.
#define C
Definition: RandGen.cpp:39
#define NC_GEOM
Definition: WM_types.h:294
#define ND_DATA
Definition: WM_types.h:408
#define NC_SCENE
Definition: WM_types.h:279
#define ND_TOOLSETTINGS
Definition: WM_types.h:349
@ BM_SPACEARR_BMO_SET
Definition: bmesh_class.h:417
#define BM_DEFAULT_NGON_STACK_SIZE
Definition: bmesh_class.h:571
#define BM_ALL_NOLOOP
Definition: bmesh_class.h:411
@ BM_FACE
Definition: bmesh_class.h:386
@ BM_VERT
Definition: bmesh_class.h:383
@ BM_EDGE
Definition: bmesh_class.h:384
@ BM_ELEM_HIDDEN
Definition: bmesh_class.h:472
@ BM_ELEM_SELECT
Definition: bmesh_class.h:471
@ BM_ELEM_TAG
Definition: bmesh_class.h:484
#define BM_FACE_FIRST_LOOP(p)
Definition: bmesh_class.h:553
#define BM_ELEM_CD_GET_VOID_P(ele, offset)
Definition: bmesh_class.h:530
BMesh * BM_mesh_copy(BMesh *bm_old)
int BMO_error_get(BMesh *bm, const char **msg, BMOperator **op)
#define BM_elem_index_get(ele)
Definition: bmesh_inline.h:124
#define BM_elem_flag_disable(ele, hflag)
Definition: bmesh_inline.h:29
#define BM_elem_flag_test(ele, hflag)
Definition: bmesh_inline.h:26
#define BM_elem_flag_enable(ele, hflag)
Definition: bmesh_inline.h:28
void BM_data_layer_add_named(BMesh *bm, CustomData *data, int type, const char *name)
Definition: bmesh_interp.c:912
void * BM_iter_at_index(BMesh *bm, const char itype, void *data, int index)
#define BM_ITER_ELEM(ele, iter, data, itype)
#define BM_ITER_MESH(ele, iter, bm, itype)
#define BM_ITER_MESH_INDEX(ele, iter, bm, itype, indexvar)
@ BM_EDGES_OF_MESH
@ BM_VERTS_OF_MESH
@ BM_FACES_OF_MESH
@ BM_LOOPS_OF_FACE
#define BM_ITER_ELEM_INDEX(ele, iter, data, itype, indexvar)
#define BM_iter_new(iter, bm, itype, data)
ATTR_WARN_UNUSED_RESULT BMesh * bm
void BM_mesh_elem_hflag_enable_all(BMesh *bm, const char htype, const char hflag, const bool respecthide)
void BM_elem_select_set(BMesh *bm, BMElem *ele, const bool select)
void BM_mesh_select_flush(BMesh *bm)
void BM_mesh_select_mode_clean(BMesh *bm)
void BM_mesh_deselect_flush(BMesh *bm)
void BM_mesh_elem_hflag_disable_all(BMesh *bm, const char htype, const char hflag, const bool respecthide)
BMFace * BM_mesh_active_face_get(BMesh *bm, const bool is_sloppy, const bool is_selected)
void BM_mesh_select_mode_flush_ex(BMesh *bm, const short selectmode)
Select Mode Flush.
#define BM_elem_hide_set(bm, ele, hide)
Definition: bmesh_marking.h:30
void BM_mesh_data_free(BMesh *bm)
BMesh Free Mesh Data.
Definition: bmesh_mesh.c:185
void BM_mesh_clear(BMesh *bm)
BMesh Clear Mesh.
Definition: bmesh_mesh.c:281
void BM_lnorspace_invalidate(BMesh *bm, const bool do_invalidate_all)
Definition: bmesh_mesh.c:1418
BMEdge * BM_edge_at_index_find_or_table(BMesh *bm, const int index)
Definition: bmesh_mesh.c:2425
BMFace * BM_face_at_index_find_or_table(BMesh *bm, const int index)
Definition: bmesh_mesh.c:2433
BMVert * BM_vert_at_index_find_or_table(BMesh *bm, const int index)
Definition: bmesh_mesh.c:2417
void BM_mesh_normals_update(BMesh *bm)
BMesh Compute Normals.
Definition: bmesh_mesh.c:500
void BM_mesh_elem_table_ensure(BMesh *bm, const char htype)
Definition: bmesh_mesh.c:2276
void BM_mesh_elem_index_ensure(BMesh *bm, const char htype)
Definition: bmesh_mesh.c:2152
bool BM_mesh_elem_table_check(BMesh *bm)
Definition: bmesh_mesh.c:2242
BLI_INLINE BMFace * BM_face_at_index(BMesh *bm, const int index)
Definition: bmesh_mesh.h:110
BLI_INLINE BMVert * BM_vert_at_index(BMesh *bm, const int index)
Definition: bmesh_mesh.h:98
void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMeshParams *params)
void BMO_slot_buffer_hflag_enable(BMesh *bm, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const char htype, const char hflag, const bool do_flush)
BMO_FLAG_BUFFER.
void BMO_slot_buffer_hflag_disable(BMesh *bm, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, const char htype, const char hflag, const bool do_flush)
BMO_FLAG_BUFFER.
void BMO_op_exec(BMesh *bm, BMOperator *op)
BMESH OPSTACK EXEC OP.
bool BMO_op_initf(BMesh *bm, BMOperator *op, const int flag, const char *fmt,...)
void BMO_op_finish(BMesh *bm, BMOperator *op)
BMESH OPSTACK FINISH OP.
BMOpSlot * BMO_slot_get(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *identifier)
BMESH OPSTACK GET SLOT.
#define BMO_FLAG_DEFAULTS
bool BMO_op_vinitf(BMesh *bm, BMOperator *op, const int flag, const char *fmt, va_list vlist)
Format Strings for BMOperator Initialization.
ATTR_WARN_UNUSED_RESULT const void * element
BMEdge * BM_edge_exists(BMVert *v_a, BMVert *v_b)
Definition: bmesh_query.c:1995
bool BM_edge_in_face(const BMEdge *e, const BMFace *f)
Definition: bmesh_query.c:555
BMFace * BM_face_exists(BMVert **varr, int len)
Definition: bmesh_query.c:2070
ATTR_WARN_UNUSED_RESULT const BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
Scene scene
const Depsgraph * depsgraph
AnimationBackup * backup
bool EDBM_vert_color_check(BMEditMesh *em)
UvMapVert * BM_uv_vert_map_at_index(UvVertMap *vmap, uint v)
void EDBM_select_more(BMEditMesh *em, const bool use_face_step)
void EDBM_mesh_free(BMEditMesh *em)
bool EDBM_op_callf(BMEditMesh *em, wmOperator *op, const char *fmt,...)
BMElem * EDBM_elem_from_selectmode(BMEditMesh *em, BMVert *eve, BMEdge *eed, BMFace *efa)
BMElem * EDBM_elem_from_index_any_multi(ViewLayer *view_layer, int object_index, int elem_index, Object **r_obedit)
BMVert * EDBM_verts_mirror_get(BMEditMesh *em, BMVert *v)
bool BMBVH_EdgeVisible(struct BMBVHTree *tree, BMEdge *e, struct Depsgraph *depsgraph, ARegion *region, View3D *v3d, Object *obedit)
#define BM_CD_LAYER_ID
void EDBM_flag_enable_all(BMEditMesh *em, const char hflag)
bool EDBM_op_init(BMEditMesh *em, BMOperator *bmop, wmOperator *op, const char *fmt,...)
bool EDBM_op_call_and_selectf(BMEditMesh *em, wmOperator *op, const char *select_slot_out, const bool select_extend, const char *fmt,...)
BMFace * EDBM_uv_active_face_get(BMEditMesh *em, const bool sloppy, const bool selected)
void EDBM_mesh_normals_update(BMEditMesh *em)
bool EDBM_mesh_reveal(BMEditMesh *em, bool select)
void EDBM_deselect_flush(BMEditMesh *em)
void EDBM_redo_state_restore(BMBackup backup, BMEditMesh *em, int recalctess)
void EDBM_project_snap_verts(bContext *C, Depsgraph *depsgraph, ARegion *region, Object *obedit, BMEditMesh *em)
void EDBM_mesh_load_ex(Main *bmain, Object *ob, bool free_data)
UvVertMap * BM_uv_vert_map_create(BMesh *bm, const bool use_select, const bool use_winding)
static BMVert * cache_mirr_intptr_as_bmvert(const intptr_t *index_lookup, int index)
bool EDBM_op_finish(BMEditMesh *em, BMOperator *bmop, wmOperator *op, const bool do_report)
bool EDBM_uv_check(BMEditMesh *em)
void BM_uv_element_map_free(UvElementMap *element_map)
void EDBM_stats_update(BMEditMesh *em)
bool EDBM_mesh_hide(BMEditMesh *em, bool swap)
void EDBM_verts_mirror_cache_begin_ex(BMEditMesh *em, const int axis, const bool use_self, const bool use_select, const bool respecthide, const bool use_topology, float maxdist, int *r_index)
static void scale_point(float c1[3], const float p[3], const float s)
BMFace * EDBM_verts_mirror_get_face(BMEditMesh *em, BMFace *f)
void EDBM_selectmode_flush(BMEditMesh *em)
void EDBM_mesh_clear(BMEditMesh *em)
void EDBM_mesh_load(Main *bmain, Object *ob)
BMBackup EDBM_redo_state_store(BMEditMesh *em)
#define VERT_INTPTR(_v, _i)
void EDBM_verts_mirror_cache_begin(BMEditMesh *em, const int axis, const bool use_self, const bool use_select, const bool respecthide, const bool use_topology)
bool EDBM_op_call_silentf(BMEditMesh *em, const char *fmt,...)
void EDBM_verts_mirror_cache_end(BMEditMesh *em)
void EDBM_verts_mirror_cache_clear(BMEditMesh *em, BMVert *v)
int EDBM_elem_to_index_any(BMEditMesh *em, BMElem *ele)
void EDBM_update_generic(Mesh *mesh, const bool do_tessellation, const bool is_destructive)
void EDBM_select_less(BMEditMesh *em, const bool use_face_step)
UvElementMap * BM_uv_element_map_create(BMesh *bm, const Scene *scene, const bool face_selected, const bool uv_selected, const bool use_winding, const bool do_islands)
static BMFace * edge_ray_cast(struct BMBVHTree *tree, const float co[3], const float dir[3], float *r_hitout, BMEdge *e)
bool EDBM_view3d_poll(bContext *C)
void EDBM_flag_disable_all(BMEditMesh *em, const char hflag)
#define BM_SEARCH_MAXDIST_MIRR
void EDBM_mesh_make(Object *ob, const int select_mode, const bool add_key_index)
void EDBM_select_flush(BMEditMesh *em)
void EDBM_selectmode_to_scene(bContext *C)
UvElement * BM_uv_element_get(UvElementMap *map, BMFace *efa, BMLoop *l)
BMEdge * EDBM_verts_mirror_get_edge(BMEditMesh *em, BMEdge *e)
void EDBM_redo_state_free(BMBackup *backup, BMEditMesh *em, int recalctess)
void EDBM_verts_mirror_apply(BMEditMesh *em, const int sel_from, const int sel_to)
void BM_uv_vert_map_free(UvVertMap *vmap)
BMElem * EDBM_elem_from_index_any(BMEditMesh *em, int index)
void EDBM_selectmode_flush_ex(BMEditMesh *em, const short selectmode)
int EDBM_elem_to_index_any_multi(ViewLayer *view_layer, BMEditMesh *em, BMElem *ele, int *r_object_index)
void * tree
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:47
static ulong * next
static MirrTopoStore_t mesh_topo_store
Definition: meshtools.c:848
static unsigned a[3]
Definition: RandGen.cpp:92
static double epsilon
_W64 int intptr_t
Definition: stdint.h:121
void * regiondata
short selectmode
Definition: BKE_editmesh.h:72
int emcopyusers
Definition: BKE_editmesh.h:56
struct BMLoop *(* looptris)[3]
Definition: BKE_editmesh.h:60
struct BMesh * bm
Definition: BKE_editmesh.h:52
short mat_nr
Definition: BKE_editmesh.h:73
struct BMEditMesh * emcopy
Definition: BKE_editmesh.h:55
int mirror_cdlayer
Definition: BKE_editmesh.h:76
struct BMEditSelection * next
Definition: bmesh_marking.h:24
BMHeader head
Definition: bmesh_class.h:255
int len
Definition: bmesh_class.h:279
char htype
Definition: bmesh_class.h:76
void * data
Definition: bmesh_class.h:63
struct BMVert * v
Definition: bmesh_class.h:165
struct BMFace * f
Definition: bmesh_class.h:183
struct BMLoop * next
Definition: bmesh_class.h:245
eBMOpSlotSubType_Union slot_subtype
struct BMOpSlot slots_out[BMO_OP_MAX_SLOTS]
float co[3]
Definition: bmesh_class.h:99
BMHeader head
Definition: bmesh_class.h:97
int totvert
Definition: bmesh_class.h:297
int totfacesel
Definition: bmesh_class.h:298
int shapenr
Definition: bmesh_class.h:353
char elem_index_dirty
Definition: bmesh_class.h:305
CustomData vdata
Definition: bmesh_class.h:337
int totedge
Definition: bmesh_class.h:297
char elem_table_dirty
Definition: bmesh_class.h:311
ListBase selected
Definition: bmesh_class.h:356
int totvertsel
Definition: bmesh_class.h:298
short selectmode
Definition: bmesh_class.h:350
BMVert ** vtable
Definition: bmesh_class.h:321
int totedgesel
Definition: bmesh_class.h:298
char spacearr_dirty
Definition: bmesh_class.h:344
CustomData ldata
Definition: bmesh_class.h:337
int totface
Definition: bmesh_class.h:297
struct Object * object
CustomDataLayer * layers
void * next
Definition: DNA_ID.h:274
ListBase block
void * first
Definition: DNA_listBase.h:47
Definition: BKE_main.h:116
ListBase meshes
Definition: BKE_main.h:149
ListBase objects
Definition: BKE_main.h:148
struct BMEditMesh * edit_mesh
struct Key * key
intptr_t * index_lookup
Definition: ED_mesh.h:329
float imat[4][4]
short shapenr
float obmat[4][4]
void * data
struct ToolSettings * toolsettings
const struct ARegion * region
struct UvElement * buf
struct UvElement ** vert
unsigned int island
unsigned short loop_of_poly_index
struct UvElement * next
struct BMLoop * l
struct UvMapVert * next
unsigned short loop_of_poly_index
unsigned int poly_index
struct UvMapVert * buf
struct UvMapVert ** vert
struct ReportList * reports
eBMOpSlotSubType_Elem elem
__forceinline const avxb select(const avxb &m, const avxb &t, const avxb &f)
Definition: util_avxb.h:167
void WM_main_add_notifier(unsigned int type, void *reference)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)