Blender  V3.3
editmesh_utils.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2004 Blender Foundation. All rights reserved. */
3 
8 #include "MEM_guardedalloc.h"
9 
10 #include "DNA_key_types.h"
11 #include "DNA_mesh_types.h"
12 #include "DNA_meshdata_types.h"
13 #include "DNA_object_types.h"
14 
15 #include "BLI_alloca.h"
16 #include "BLI_buffer.h"
17 #include "BLI_kdtree.h"
18 #include "BLI_listbase.h"
19 #include "BLI_math.h"
20 
21 #include "BKE_DerivedMesh.h"
22 #include "BKE_context.h"
23 #include "BKE_customdata.h"
24 #include "BKE_editmesh.h"
25 #include "BKE_editmesh_bvh.h"
26 #include "BKE_global.h"
27 #include "BKE_layer.h"
28 #include "BKE_main.h"
29 #include "BKE_mesh.h"
30 #include "BKE_mesh_mapping.h"
31 #include "BKE_report.h"
32 
33 #include "DEG_depsgraph.h"
34 
35 #include "BKE_object.h" /* XXX. only for EDBM_mesh_load(). */
36 
37 #include "WM_api.h"
38 #include "WM_types.h"
39 
40 #include "ED_mesh.h"
41 #include "ED_screen.h"
43 #include "ED_uvedit.h"
44 #include "ED_view3d.h"
45 
46 #include "mesh_intern.h" /* own include */
47 
48 /* -------------------------------------------------------------------- */
52 /* Mesh backup implementation.
53  * This would greatly benefit from some sort of binary diffing
54  * just as the undo stack would.
55  * So leaving this as an interface for further work */
56 
58 {
60  backup.bmcopy = BM_mesh_copy(em->bm);
61  return backup;
62 }
63 
64 void EDBM_redo_state_restore(BMBackup *backup, BMEditMesh *em, bool recalc_looptri)
65 {
66  BMesh *tmpbm;
67 
68  BM_mesh_data_free(em->bm);
69  tmpbm = BM_mesh_copy(backup->bmcopy);
70  *em->bm = *tmpbm;
71  MEM_freeN(tmpbm);
72  tmpbm = NULL;
73 
74  if (recalc_looptri) {
76  }
77 }
78 
80 {
81  BM_mesh_data_free(em->bm);
82  *em->bm = *backup->bmcopy;
83  MEM_freeN(backup->bmcopy);
84  backup->bmcopy = NULL;
85  if (recalc_looptri) {
87  }
88 }
89 
91 {
92  if (backup->bmcopy) {
93  BM_mesh_data_free(backup->bmcopy);
94  MEM_freeN(backup->bmcopy);
95  }
96 }
97 
100 /* -------------------------------------------------------------------- */
104 bool EDBM_op_init(BMEditMesh *em, BMOperator *bmop, wmOperator *op, const char *fmt, ...)
105 {
106  BMesh *bm = em->bm;
107  va_list list;
108 
109  va_start(list, fmt);
110 
111  if (!BMO_op_vinitf(bm, bmop, BMO_FLAG_DEFAULTS, fmt, list)) {
112  BKE_reportf(op->reports, RPT_ERROR, "Parse error in %s", __func__);
113  va_end(list);
114  return false;
115  }
116 
117  va_end(list);
118 
119  return true;
120 }
121 
122 bool EDBM_op_finish(BMEditMesh *em, BMOperator *bmop, wmOperator *op, const bool do_report)
123 {
124  const char *errmsg;
125 
126 #ifndef NDEBUG
127  struct {
128  int verts_len, edges_len, loops_len, faces_len;
129  } em_state_prev = {
130  .verts_len = em->bm->totvert,
131  .edges_len = em->bm->totedge,
132  .loops_len = em->bm->totloop,
133  .faces_len = em->bm->totface,
134  };
135 #endif
136 
137  BMO_op_finish(em->bm, bmop);
138 
139  bool changed = false;
140  bool changed_was_set = false;
141 
142  eBMOpErrorLevel level;
143  while (BMO_error_pop(em->bm, &errmsg, NULL, &level)) {
145  switch (level) {
146  case BMO_ERROR_CANCEL: {
147  changed_was_set = true;
148  break;
149  }
150  case BMO_ERROR_WARN: {
151  type = RPT_WARNING;
152  changed_was_set = true;
153  changed = true;
154  break;
155  }
156  case BMO_ERROR_FATAL: {
157  type = RPT_ERROR;
158  changed_was_set = true;
159  changed = true;
160  break;
161  }
162  }
163 
164  if (do_report) {
165  BKE_report(op->reports, type, errmsg);
166  }
167  }
168  if (changed_was_set == false) {
169  changed = true;
170  }
171 
172 #ifndef NDEBUG
173  if (changed == false) {
174  BLI_assert((em_state_prev.verts_len == em->bm->totvert) &&
175  (em_state_prev.edges_len == em->bm->totedge) &&
176  (em_state_prev.loops_len == em->bm->totloop) &&
177  (em_state_prev.faces_len == em->bm->totface));
178  }
179 #endif
180 
181  return changed;
182 }
183 
184 bool EDBM_op_callf(BMEditMesh *em, wmOperator *op, const char *fmt, ...)
185 {
186  BMesh *bm = em->bm;
187  BMOperator bmop;
188  va_list list;
189 
190  va_start(list, fmt);
191 
192  if (!BMO_op_vinitf(bm, &bmop, BMO_FLAG_DEFAULTS, fmt, list)) {
193  BKE_reportf(op->reports, RPT_ERROR, "Parse error in %s", __func__);
194  va_end(list);
195  return false;
196  }
197 
198  BMO_op_exec(bm, &bmop);
199 
200  va_end(list);
201  return EDBM_op_finish(em, &bmop, op, true);
202 }
203 
205  wmOperator *op,
206  const char *select_slot_out,
207  const bool select_extend,
208  const char *fmt,
209  ...)
210 {
211  BMOpSlot *slot_select_out;
212  BMesh *bm = em->bm;
213  BMOperator bmop;
214  va_list list;
215  char hflag;
216 
217  va_start(list, fmt);
218 
219  if (!BMO_op_vinitf(bm, &bmop, BMO_FLAG_DEFAULTS, fmt, list)) {
220  BKE_reportf(op->reports, RPT_ERROR, "Parse error in %s", __func__);
221  va_end(list);
222  return false;
223  }
224 
225  BMO_op_exec(bm, &bmop);
226 
227  slot_select_out = BMO_slot_get(bmop.slots_out, select_slot_out);
228  hflag = slot_select_out->slot_subtype.elem & BM_ALL_NOLOOP;
229  BLI_assert(hflag != 0);
230 
231  if (select_extend == false) {
233  }
234 
236  em->bm, bmop.slots_out, select_slot_out, hflag, BM_ELEM_SELECT, true);
237 
238  va_end(list);
239  return EDBM_op_finish(em, &bmop, op, true);
240 }
241 
242 bool EDBM_op_call_silentf(BMEditMesh *em, const char *fmt, ...)
243 {
244  BMesh *bm = em->bm;
245  BMOperator bmop;
246  va_list list;
247 
248  va_start(list, fmt);
249 
250  if (!BMO_op_vinitf(bm, &bmop, BMO_FLAG_DEFAULTS, fmt, list)) {
251  va_end(list);
252  return false;
253  }
254 
255  BMO_op_exec(bm, &bmop);
256 
257  va_end(list);
258  return EDBM_op_finish(em, &bmop, NULL, false);
259 }
260 
263 /* -------------------------------------------------------------------- */
269 void EDBM_mesh_make(Object *ob, const int select_mode, const bool add_key_index)
270 {
271  Mesh *me = ob->data;
272  BMesh *bm;
273 
274  bm = BKE_mesh_to_bmesh(me,
275  ob,
276  add_key_index,
277  &((struct BMeshCreateParams){
278  .use_toolflags = true,
279  }));
280 
281  if (me->edit_mesh) {
282  /* this happens when switching shape keys */
284  MEM_freeN(me->edit_mesh);
285  }
286 
287  /* Executing operators re-tessellates,
288  * so we can avoid doing here but at some point it may need to be added back. */
290 
291  me->edit_mesh->selectmode = me->edit_mesh->bm->selectmode = select_mode;
292  me->edit_mesh->mat_nr = (ob->actcol > 0) ? ob->actcol - 1 : 0;
293 
294  /* we need to flush selection because the mode may have changed from when last in editmode */
296 }
297 
298 void EDBM_mesh_load_ex(Main *bmain, Object *ob, bool free_data)
299 {
300  Mesh *me = ob->data;
301  BMesh *bm = me->edit_mesh->bm;
302 
303  /* Workaround for T42360, 'ob->shapenr' should be 1 in this case.
304  * however this isn't synchronized between objects at the moment. */
305  if (UNLIKELY((ob->shapenr == 0) && (me->key && !BLI_listbase_is_empty(&me->key->block)))) {
306  bm->shapenr = 1;
307  }
308 
309  BM_mesh_bm_to_me(bmain,
310  bm,
311  me,
312  (&(struct BMeshToMeshParams){
313  .calc_object_remap = true,
314  .update_shapekey_indices = !free_data,
315  }));
316 }
317 
319 {
320  /* clear bmesh */
321  BM_mesh_clear(em->bm);
322 
323  /* free tessellation data */
324  em->tottri = 0;
325  MEM_SAFE_FREE(em->looptris);
326 }
327 
328 void EDBM_mesh_load(Main *bmain, Object *ob)
329 {
330  EDBM_mesh_load_ex(bmain, ob, true);
331 }
332 
334 {
335  /* These tables aren't used yet, so it's not strictly necessary
336  * to 'end' them but if someone tries to start using them,
337  * having these in place will save a lot of pain. */
340 
342 }
343 
346 /* -------------------------------------------------------------------- */
351 {
353  Object *obedit = CTX_data_edit_object(C);
354  BMEditMesh *em = BKE_editmesh_from_object(obedit);
355 
356  if (!em) {
357  return;
358  }
359 
361 
362  /* Request redraw of header buttons (to show new select mode) */
364 }
365 
366 void EDBM_selectmode_flush_ex(BMEditMesh *em, const short selectmode)
367 {
369 }
370 
372 {
374 }
375 
377 {
378  /* function below doesn't use. just do this to keep the values in sync */
379  em->bm->selectmode = em->selectmode;
381 }
382 
384 {
385  /* function below doesn't use. just do this to keep the values in sync */
386  em->bm->selectmode = em->selectmode;
388 }
389 
390 void EDBM_select_more(BMEditMesh *em, const bool use_face_step)
391 {
392  BMOperator bmop;
393  const bool use_faces = (em->selectmode == SCE_SELECT_FACE);
394 
395  BMO_op_initf(em->bm,
396  &bmop,
398  "region_extend geom=%hvef use_contract=%b use_faces=%b use_face_step=%b",
400  false,
401  use_faces,
402  use_face_step);
403  BMO_op_exec(em->bm, &bmop);
404  /* Don't flush selection in edge/vertex mode. */
406  em->bm, bmop.slots_out, "geom.out", BM_ALL_NOLOOP, BM_ELEM_SELECT, use_faces ? true : false);
407  BMO_op_finish(em->bm, &bmop);
408 
410 }
411 
412 void EDBM_select_less(BMEditMesh *em, const bool use_face_step)
413 {
414  BMOperator bmop;
415  const bool use_faces = (em->selectmode == SCE_SELECT_FACE);
416 
417  BMO_op_initf(em->bm,
418  &bmop,
420  "region_extend geom=%hvef use_contract=%b use_faces=%b use_face_step=%b",
422  true,
423  use_faces,
424  use_face_step);
425  BMO_op_exec(em->bm, &bmop);
426  /* Don't flush selection in edge/vertex mode. */
428  em->bm, bmop.slots_out, "geom.out", BM_ALL_NOLOOP, BM_ELEM_SELECT, use_faces ? true : false);
429  BMO_op_finish(em->bm, &bmop);
430 
432 
433  /* only needed for select less, ensure we don't have isolated elements remaining */
435 }
436 
437 void EDBM_flag_disable_all(BMEditMesh *em, const char hflag)
438 {
439  BM_mesh_elem_hflag_disable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, hflag, false);
440 }
441 
442 void EDBM_flag_enable_all(BMEditMesh *em, const char hflag)
443 {
444  BM_mesh_elem_hflag_enable_all(em->bm, BM_VERT | BM_EDGE | BM_FACE, hflag, true);
445 }
446 
449 /* -------------------------------------------------------------------- */
453 UvVertMap *BM_uv_vert_map_create(BMesh *bm, const bool use_select, const bool use_winding)
454 {
455  BMVert *ev;
456  BMFace *efa;
457  BMLoop *l;
458  BMIter iter, liter;
459  /* vars from original func */
460  UvVertMap *vmap;
461  UvMapVert *buf;
462  const MLoopUV *luv;
463  uint a;
464  int totverts, i, totuv, totfaces;
465  const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
466  bool *winding = NULL;
468 
470 
471  totfaces = bm->totface;
472  totverts = bm->totvert;
473  totuv = 0;
474 
475  /* generate UvMapVert array */
476  BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
477  if ((use_select == false) || BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
478  totuv += efa->len;
479  }
480  }
481 
482  if (totuv == 0) {
483  return NULL;
484  }
485  vmap = (UvVertMap *)MEM_callocN(sizeof(*vmap), "UvVertMap");
486  if (!vmap) {
487  return NULL;
488  }
489 
490  vmap->vert = (UvMapVert **)MEM_callocN(sizeof(*vmap->vert) * totverts, "UvMapVert_pt");
491  buf = vmap->buf = (UvMapVert *)MEM_callocN(sizeof(*vmap->buf) * totuv, "UvMapVert");
492  if (use_winding) {
493  winding = MEM_callocN(sizeof(*winding) * totfaces, "winding");
494  }
495 
496  if (!vmap->vert || !vmap->buf) {
498  return NULL;
499  }
500 
501  BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, a) {
502  if ((use_select == false) || BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
503  float(*tf_uv)[2] = NULL;
504 
505  if (use_winding) {
506  tf_uv = (float(*)[2])BLI_buffer_reinit_data(&tf_uv_buf, vec2f, efa->len);
507  }
508 
509  BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
510  buf->loop_of_poly_index = i;
511  buf->poly_index = a;
512  buf->separate = 0;
513 
514  buf->next = vmap->vert[BM_elem_index_get(l->v)];
515  vmap->vert[BM_elem_index_get(l->v)] = buf;
516  buf++;
517 
518  if (use_winding) {
519  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
520  copy_v2_v2(tf_uv[i], luv->uv);
521  }
522  }
523 
524  if (use_winding) {
525  winding[a] = cross_poly_v2(tf_uv, efa->len) > 0;
526  }
527  }
528  }
529 
530  /* sort individual uvs for each vert */
531  BM_ITER_MESH_INDEX (ev, &iter, bm, BM_VERTS_OF_MESH, a) {
532  UvMapVert *newvlist = NULL, *vlist = vmap->vert[a];
533  UvMapVert *iterv, *v, *lastv, *next;
534  const float *uv, *uv2;
535 
536  while (vlist) {
537  v = vlist;
538  vlist = vlist->next;
539  v->next = newvlist;
540  newvlist = v;
541 
542  efa = BM_face_at_index(bm, v->poly_index);
543 
544  l = BM_iter_at_index(bm, BM_LOOPS_OF_FACE, efa, v->loop_of_poly_index);
545  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
546  uv = luv->uv;
547 
548  lastv = NULL;
549  iterv = vlist;
550 
551  while (iterv) {
552  next = iterv->next;
553  efa = BM_face_at_index(bm, iterv->poly_index);
555  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
556  uv2 = luv->uv;
557 
558  if (compare_v2v2(uv2, uv, STD_UV_CONNECT_LIMIT) &&
559  (!use_winding || winding[iterv->poly_index] == winding[v->poly_index])) {
560  if (lastv) {
561  lastv->next = next;
562  }
563  else {
564  vlist = next;
565  }
566  iterv->next = newvlist;
567  newvlist = iterv;
568  }
569  else {
570  lastv = iterv;
571  }
572 
573  iterv = next;
574  }
575 
576  newvlist->separate = 1;
577  }
578 
579  vmap->vert[a] = newvlist;
580  }
581 
582  if (use_winding) {
583  MEM_freeN(winding);
584  }
585 
586  BLI_buffer_free(&tf_uv_buf);
587 
588  return vmap;
589 }
590 
592 {
593  return vmap->vert[v];
594 }
595 
596 #define INVALID_ISLAND ((unsigned int)-1)
597 
598 static void bm_uv_assign_island(UvElementMap *element_map,
600  int nisland,
601  uint *map,
602  UvElement *islandbuf,
603  int islandbufsize)
604 {
605  element->island = nisland;
606  map[element - element_map->buf] = islandbufsize;
607 
608  /* Copy *element to islandbuf[islandbufsize]. */
609  islandbuf[islandbufsize].l = element->l;
610  islandbuf[islandbufsize].separate = element->separate;
611  islandbuf[islandbufsize].loop_of_poly_index = element->loop_of_poly_index;
612  islandbuf[islandbufsize].island = element->island;
613  islandbuf[islandbufsize].flag = element->flag;
614 }
615 
617  const Scene *scene,
618  UvElement *islandbuf,
619  uint *map,
620  bool uv_selected,
621  int cd_loop_uv_offset)
622 {
623  int totuv = element_map->totalUVs;
624 
625  /* For each UvElement, locate the "separate" UvElement that precedes it in the linked list. */
626  UvElement **head_table = MEM_mallocN(sizeof(*head_table) * totuv, "uv_island_head_table");
627  for (int i = 0; i < totuv; i++) {
628  UvElement *head = element_map->buf + i;
629  if (head->separate) {
630  UvElement *element = head;
631  while (element) {
632  head_table[element - element_map->buf] = head;
633  element = element->next;
634  if (element && element->separate) {
635  break;
636  }
637  }
638  }
639  }
640 
641  /* Depth first search the graph, building islands as we go. */
642  int nislands = 0;
643  int islandbufsize = 0;
644  int stack_upper_bound = totuv;
645  UvElement **stack_uv = MEM_mallocN(sizeof(*stack_uv) * stack_upper_bound,
646  "uv_island_element_stack");
647  int stacksize_uv = 0;
648  for (int i = 0; i < totuv; i++) {
649  UvElement *element = element_map->buf + i;
650  if (element->island != INVALID_ISLAND) {
651  /* Unique UV (element and all it's children) are already part of an island. */
652  continue;
653  }
654 
655  /* Create a new island, i.e. nislands++. */
656 
657  BLI_assert(element->separate); /* Ensure we're the head of this unique UV. */
658 
659  /* Seed the graph search. */
660  stack_uv[stacksize_uv++] = element;
661  while (element) {
662  bm_uv_assign_island(element_map, element, nislands, map, islandbuf, islandbufsize++);
663  element = element->next;
664  if (element && element->separate) {
665  break;
666  }
667  }
668 
669  /* Traverse the graph. */
670  while (stacksize_uv) {
671  BLI_assert(stacksize_uv < stack_upper_bound);
672  element = stack_uv[--stacksize_uv];
673  while (element) {
674 
675  /* Scan forwards around the BMFace that contains element->l. */
676  if (!uv_selected || uvedit_edge_select_test(scene, element->l, cd_loop_uv_offset)) {
677  UvElement *next = BM_uv_element_get(element_map, element->l->next->f, element->l->next);
678  if (next->island == INVALID_ISLAND) {
679  UvElement *tail = head_table[next - element_map->buf];
680  stack_uv[stacksize_uv++] = tail;
681  while (tail) {
682  bm_uv_assign_island(element_map, tail, nislands, map, islandbuf, islandbufsize++);
683  tail = tail->next;
684  if (tail && tail->separate) {
685  break;
686  }
687  }
688  }
689  }
690 
691  /* Scan backwards around the BMFace that contains element->l. */
692  if (!uv_selected || uvedit_edge_select_test(scene, element->l->prev, cd_loop_uv_offset)) {
693  UvElement *prev = BM_uv_element_get(element_map, element->l->prev->f, element->l->prev);
694  if (prev->island == INVALID_ISLAND) {
695  UvElement *tail = head_table[prev - element_map->buf];
696  stack_uv[stacksize_uv++] = tail;
697  while (tail) {
698  bm_uv_assign_island(element_map, tail, nislands, map, islandbuf, islandbufsize++);
699  tail = tail->next;
700  if (tail && tail->separate) {
701  break;
702  }
703  }
704  }
705  }
706 
707  /* The same for all the UvElements in this unique UV. */
708  element = element->next;
709  if (element && element->separate) {
710  break;
711  }
712  }
713  }
714  nislands++;
715  }
716  BLI_assert(islandbufsize == totuv);
717 
718  MEM_SAFE_FREE(stack_uv);
719  MEM_SAFE_FREE(head_table);
720 
721  return nislands;
722 }
723 
725  const Scene *scene,
726  const bool uv_selected,
727  const bool use_winding,
728  const bool do_islands)
729 {
730  /* In uv sync selection, all UVs (from unhidden geometry) are visible. */
731  const bool face_selected = !(scene->toolsettings->uv_flag & UV_SYNC_SELECTION);
732 
733  BMVert *ev;
734  BMFace *efa;
735  BMLoop *l;
736  BMIter iter, liter;
737  /* vars from original func */
738  UvElementMap *element_map;
739  UvElement *buf;
740  bool *winding = NULL;
742 
743  MLoopUV *luv;
744  int totverts, totfaces, i, totuv, j;
745 
746  const int cd_loop_uv_offset = CustomData_get_offset(&bm->ldata, CD_MLOOPUV);
747 
749 
750  totfaces = bm->totface;
751  totverts = bm->totvert;
752  totuv = 0;
753 
754  /* generate UvElement array */
755  BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
756  if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
757  continue;
758  }
759 
760  if (face_selected && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
761  continue;
762  }
763 
764  if (!uv_selected) {
765  totuv += efa->len;
766  }
767  else {
768  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
769  if (uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
770  totuv++;
771  }
772  }
773  }
774  }
775 
776  if (totuv == 0) {
777  return NULL;
778  }
779 
780  element_map = (UvElementMap *)MEM_callocN(sizeof(*element_map), "UvElementMap");
781  element_map->totalUVs = totuv;
782  element_map->vert = (UvElement **)MEM_callocN(sizeof(*element_map->vert) * totverts,
783  "UvElementVerts");
784  buf = element_map->buf = (UvElement *)MEM_callocN(sizeof(*element_map->buf) * totuv,
785  "UvElement");
786 
787  if (use_winding) {
788  winding = MEM_callocN(sizeof(*winding) * totfaces, "winding");
789  }
790 
791  BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, j) {
792 
793  if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) {
794  continue;
795  }
796 
797  if (face_selected && !BM_elem_flag_test(efa, BM_ELEM_SELECT)) {
798  continue;
799  }
800 
801  float(*tf_uv)[2] = NULL;
802 
803  if (use_winding) {
804  tf_uv = (float(*)[2])BLI_buffer_reinit_data(&tf_uv_buf, vec2f, efa->len);
805  }
806 
807  BM_ITER_ELEM_INDEX (l, &liter, efa, BM_LOOPS_OF_FACE, i) {
808  if (uv_selected && !uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
809  continue;
810  }
811 
812  buf->l = l;
813  buf->separate = 0;
814  buf->island = INVALID_ISLAND;
815  buf->loop_of_poly_index = i;
816 
817  buf->next = element_map->vert[BM_elem_index_get(l->v)];
818  element_map->vert[BM_elem_index_get(l->v)] = buf;
819 
820  if (use_winding) {
821  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
822  copy_v2_v2(tf_uv[i], luv->uv);
823  }
824 
825  buf++;
826  }
827 
828  if (winding) {
829  winding[j] = cross_poly_v2(tf_uv, efa->len) > 0;
830  }
831  }
832 
833  /* sort individual uvs for each vert */
834  BM_ITER_MESH_INDEX (ev, &iter, bm, BM_VERTS_OF_MESH, i) {
835  UvElement *newvlist = NULL, *vlist = element_map->vert[i];
836  UvElement *iterv, *v, *lastv, *next;
837  const float *uv, *uv2;
838  bool uv_vert_sel, uv2_vert_sel;
839 
840  while (vlist) {
841  v = vlist;
842  vlist = vlist->next;
843  v->next = newvlist;
844  newvlist = v;
845 
846  l = v->l;
847  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
848  uv = luv->uv;
849  uv_vert_sel = uvedit_uv_select_test(scene, l, cd_loop_uv_offset);
850 
851  lastv = NULL;
852  iterv = vlist;
853 
854  while (iterv) {
855  next = iterv->next;
856 
857  l = iterv->l;
858  luv = BM_ELEM_CD_GET_VOID_P(l, cd_loop_uv_offset);
859  uv2 = luv->uv;
860  uv2_vert_sel = uvedit_uv_select_test(scene, l, cd_loop_uv_offset);
861 
862  /* Check if the uv loops share the same selection state (if not, they are not connected as
863  * they have been ripped or other edit commands have separated them). */
864  const bool connected = (uv_vert_sel == uv2_vert_sel) &&
866 
867  if (connected && (!use_winding || winding[BM_elem_index_get(iterv->l->f)] ==
868  winding[BM_elem_index_get(v->l->f)])) {
869  if (lastv) {
870  lastv->next = next;
871  }
872  else {
873  vlist = next;
874  }
875  iterv->next = newvlist;
876  newvlist = iterv;
877  }
878  else {
879  lastv = iterv;
880  }
881 
882  iterv = next;
883  }
884 
885  newvlist->separate = 1;
886  }
887 
888  element_map->vert[i] = newvlist;
889  }
890 
891  if (use_winding) {
892  MEM_freeN(winding);
893  }
894 
895  if (do_islands) {
896  uint *map;
897  BMFace **stack;
898  int stacksize = 0;
899  UvElement *islandbuf;
900  /* island number for faces */
901  int *island_number = NULL;
902 
903  int nislands = 0, islandbufsize = 0;
904 
905  /* map holds the map from current vmap->buf to the new, sorted map */
906  map = MEM_mallocN(sizeof(*map) * totuv, "uvelement_remap");
907  stack = MEM_mallocN(sizeof(*stack) * bm->totface, "uv_island_face_stack");
908  islandbuf = MEM_callocN(sizeof(*islandbuf) * totuv, "uvelement_island_buffer");
909  island_number = MEM_mallocN(sizeof(*island_number) * totfaces, "uv_island_number_face");
910  copy_vn_i(island_number, totfaces, INVALID_ISLAND);
911 
912  const bool use_uv_edge_connectivity = scene->toolsettings->uv_flag & UV_SYNC_SELECTION ?
915  if (use_uv_edge_connectivity) {
917  element_map, scene, islandbuf, map, uv_selected, cd_loop_uv_offset);
918  islandbufsize = totuv;
919  }
920 
921  /* at this point, every UvElement in vert points to a UvElement sharing the same vertex.
922  * Now we should sort uv's in islands. */
923  for (i = 0; i < totuv; i++) {
924  if (element_map->buf[i].island == INVALID_ISLAND) {
925  element_map->buf[i].island = nislands;
926  stack[0] = element_map->buf[i].l->f;
927  island_number[BM_elem_index_get(stack[0])] = nislands;
928  stacksize = 1;
929 
930  while (stacksize > 0) {
931  efa = stack[--stacksize];
932 
933  BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
934  if (uv_selected && !uvedit_uv_select_test(scene, l, cd_loop_uv_offset)) {
935  continue;
936  }
937 
938  UvElement *element, *initelement = element_map->vert[BM_elem_index_get(l->v)];
939 
940  for (element = initelement; element; element = element->next) {
941  if (element->separate) {
942  initelement = element;
943  }
944 
945  if (element->l->f == efa) {
946  /* found the uv corresponding to our face and vertex.
947  * Now fill it to the buffer */
949  element_map, element, nislands, map, islandbuf, islandbufsize++);
950 
951  for (element = initelement; element; element = element->next) {
952  if (element->separate && element != initelement) {
953  break;
954  }
955 
956  if (island_number[BM_elem_index_get(element->l->f)] == INVALID_ISLAND) {
957  stack[stacksize++] = element->l->f;
958  island_number[BM_elem_index_get(element->l->f)] = nislands;
959  }
960  }
961  break;
962  }
963  }
964  }
965  }
966 
967  nislands++;
968  }
969  }
970 
971  MEM_freeN(island_number);
972 
973  /* remap */
974  for (i = 0; i < bm->totvert; i++) {
975  /* important since we may do selection only. Some of these may be NULL */
976  if (element_map->vert[i]) {
977  element_map->vert[i] = &islandbuf[map[element_map->vert[i] - element_map->buf]];
978  }
979  }
980 
981  element_map->islandIndices = MEM_callocN(sizeof(*element_map->islandIndices) * nislands,
982  "UvElementMap_island_indices");
983  j = 0;
984  for (i = 0; i < totuv; i++) {
985  UvElement *element = element_map->buf[i].next;
986  if (element == NULL) {
987  islandbuf[map[i]].next = NULL;
988  }
989  else {
990  islandbuf[map[i]].next = &islandbuf[map[element - element_map->buf]];
991  }
992 
993  if (islandbuf[i].island != j) {
994  j++;
995  element_map->islandIndices[j] = i;
996  }
997  }
998 
999  MEM_freeN(element_map->buf);
1000 
1001  element_map->buf = islandbuf;
1002  element_map->totalIslands = nislands;
1003  MEM_freeN(stack);
1004  MEM_freeN(map);
1005  }
1006 
1007  BLI_buffer_free(&tf_uv_buf);
1008 
1009  return element_map;
1010 }
1011 
1013 {
1014  if (vmap) {
1015  if (vmap->vert) {
1016  MEM_freeN(vmap->vert);
1017  }
1018  if (vmap->buf) {
1019  MEM_freeN(vmap->buf);
1020  }
1021  MEM_freeN(vmap);
1022  }
1023 }
1024 
1026 {
1027  if (element_map) {
1028  if (element_map->vert) {
1029  MEM_freeN(element_map->vert);
1030  }
1031  if (element_map->buf) {
1032  MEM_freeN(element_map->buf);
1033  }
1034  if (element_map->islandIndices) {
1035  MEM_freeN(element_map->islandIndices);
1036  }
1037  MEM_freeN(element_map);
1038  }
1039 }
1040 
1042 {
1043  for (UvElement *element = map->vert[BM_elem_index_get(l->v)]; element; element = element->next) {
1044  if (element->l->f == efa) {
1045  return element;
1046  }
1047  }
1048 
1049  return NULL;
1050 }
1051 
1054 /* -------------------------------------------------------------------- */
1058 BMFace *EDBM_uv_active_face_get(BMEditMesh *em, const bool sloppy, const bool selected)
1059 {
1060  BMFace *efa = NULL;
1061 
1062  if (!EDBM_uv_check(em)) {
1063  return NULL;
1064  }
1065 
1066  efa = BM_mesh_active_face_get(em->bm, sloppy, selected);
1067 
1068  if (efa) {
1069  return efa;
1070  }
1071 
1072  return NULL;
1073 }
1074 
1076 {
1077  /* some of these checks could be a touch overkill */
1078  return em && em->bm->totface && CustomData_has_layer(&em->bm->ldata, CD_MLOOPUV);
1079 }
1080 
1082 {
1083  /* some of these checks could be a touch overkill */
1084  return em && em->bm->totface && CustomData_has_layer(&em->bm->ldata, CD_PROP_BYTE_COLOR);
1085 }
1086 
1089 /* -------------------------------------------------------------------- */
1093 static BMVert *cache_mirr_intptr_as_bmvert(const intptr_t *index_lookup, int index)
1094 {
1095  intptr_t eve_i = index_lookup[index];
1096  return (eve_i == -1) ? NULL : (BMVert *)eve_i;
1097 }
1098 
1115 /* BM_SEARCH_MAXDIST is too big, copied from 2.6x MOC_THRESH, should become a preference. */
1116 #define BM_SEARCH_MAXDIST_MIRR 0.00002f
1117 #define BM_CD_LAYER_ID "__mirror_index"
1118 
1120  const int axis,
1121  const bool use_self,
1122  const bool use_select,
1123  const bool respecthide,
1124  /* extra args */
1125  const bool use_topology,
1126  float maxdist,
1127  int *r_index)
1128 {
1129  BMesh *bm = em->bm;
1130  BMIter iter;
1131  BMVert *v;
1132  int cd_vmirr_offset = 0;
1133  int i;
1134  const float maxdist_sq = square_f(maxdist);
1135 
1136  /* one or the other is used depending if topo is enabled */
1137  KDTree_3d *tree = NULL;
1138  MirrTopoStore_t mesh_topo_store = {NULL, -1, -1, -1};
1139 
1141 
1142  if (r_index == NULL) {
1143  const char *layer_id = BM_CD_LAYER_ID;
1145  if (em->mirror_cdlayer == -1) {
1148  }
1149 
1150  cd_vmirr_offset = CustomData_get_n_offset(
1151  &bm->vdata,
1152  CD_PROP_INT32,
1154 
1156  }
1157 
1159 
1160  if (use_topology) {
1162  }
1163  else {
1164  tree = BLI_kdtree_3d_new(bm->totvert);
1165  BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
1166  if (respecthide && BM_elem_flag_test(v, BM_ELEM_HIDDEN)) {
1167  continue;
1168  }
1169 
1170  BLI_kdtree_3d_insert(tree, i, v->co);
1171  }
1172  BLI_kdtree_3d_balance(tree);
1173  }
1174 
1175 #define VERT_INTPTR(_v, _i) (r_index ? &r_index[_i] : BM_ELEM_CD_GET_VOID_P(_v, cd_vmirr_offset))
1176 
1177  BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
1178  if (respecthide && BM_elem_flag_test(v, BM_ELEM_HIDDEN)) {
1179  continue;
1180  }
1181 
1182  if (use_select && !BM_elem_flag_test(v, BM_ELEM_SELECT)) {
1183  continue;
1184  }
1185 
1187  BMVert *v_mirr;
1188  int *idx = VERT_INTPTR(v, i);
1189 
1190  if (use_topology) {
1192  if (v_mirr != NULL) {
1193  if (respecthide && BM_elem_flag_test(v_mirr, BM_ELEM_HIDDEN)) {
1194  v_mirr = NULL;
1195  }
1196  }
1197  }
1198  else {
1199  int i_mirr;
1200  float co[3];
1201  copy_v3_v3(co, v->co);
1202  co[axis] *= -1.0f;
1203 
1204  v_mirr = NULL;
1205  i_mirr = BLI_kdtree_3d_find_nearest(tree, co, NULL);
1206  if (i_mirr != -1) {
1207  BMVert *v_test = BM_vert_at_index(bm, i_mirr);
1208  if (len_squared_v3v3(co, v_test->co) < maxdist_sq) {
1209  v_mirr = v_test;
1210  }
1211  }
1212  }
1213 
1214  if (v_mirr && (use_self || (v_mirr != v))) {
1215  const int i_mirr = BM_elem_index_get(v_mirr);
1216  *idx = i_mirr;
1217  idx = VERT_INTPTR(v_mirr, i_mirr);
1218  *idx = i;
1219  }
1220  else {
1221  *idx = -1;
1222  }
1223  }
1224 
1225 #undef VERT_INTPTR
1226 
1227  if (use_topology) {
1229  }
1230  else {
1231  BLI_kdtree_3d_free(tree);
1232  }
1233 }
1234 
1236  const int axis,
1237  const bool use_self,
1238  const bool use_select,
1239  const bool respecthide,
1240  const bool use_topology)
1241 {
1243  axis,
1244  use_self,
1245  use_select,
1246  respecthide,
1247  /* extra args */
1248  use_topology,
1250  NULL);
1251 }
1252 
1254 {
1255  const 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 && *mirr >= 0 && *mirr < em->bm->totvert) {
1260  if (!em->bm->vtable) {
1261  printf(
1262  "err: should only be called between "
1263  "EDBM_verts_mirror_cache_begin and EDBM_verts_mirror_cache_end");
1264  return NULL;
1265  }
1266 
1267  return em->bm->vtable[*mirr];
1268  }
1269 
1270  return NULL;
1271 }
1272 
1274 {
1275  BMVert *v1_mirr, *v2_mirr;
1276  if ((v1_mirr = EDBM_verts_mirror_get(em, e->v1)) &&
1277  (v2_mirr = EDBM_verts_mirror_get(em, e->v2)) &&
1278  /* While highly unlikely, a zero length central edges vertices can match, see T89342. */
1279  LIKELY(v1_mirr != v2_mirr)) {
1280  return BM_edge_exists(v1_mirr, v2_mirr);
1281  }
1282 
1283  return NULL;
1284 }
1285 
1287 {
1288  BMVert **v_mirr_arr = BLI_array_alloca(v_mirr_arr, f->len);
1289 
1290  BMLoop *l_iter, *l_first;
1291  uint i = 0;
1292 
1293  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
1294  do {
1295  if ((v_mirr_arr[i++] = EDBM_verts_mirror_get(em, l_iter->v)) == NULL) {
1296  return NULL;
1297  }
1298  } while ((l_iter = l_iter->next) != l_first);
1299 
1300  return BM_face_exists(v_mirr_arr, f->len);
1301 }
1302 
1304 {
1305  int *mirr = CustomData_bmesh_get_layer_n(&em->bm->vdata, v->head.data, em->mirror_cdlayer);
1306 
1307  BLI_assert(em->mirror_cdlayer != -1); /* invalid use */
1308 
1309  if (mirr) {
1310  *mirr = -1;
1311  }
1312 }
1313 
1315 {
1316  em->mirror_cdlayer = -1;
1317 }
1318 
1319 void EDBM_verts_mirror_apply(BMEditMesh *em, const int sel_from, const int sel_to)
1320 {
1321  BMIter iter;
1322  BMVert *v;
1323 
1324  BLI_assert((em->bm->vtable != NULL) && ((em->bm->elem_table_dirty & BM_VERT) == 0));
1325 
1326  BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) {
1327  if (BM_elem_flag_test(v, BM_ELEM_SELECT) == sel_from) {
1328  BMVert *mirr = EDBM_verts_mirror_get(em, v);
1329  if (mirr) {
1330  if (BM_elem_flag_test(mirr, BM_ELEM_SELECT) == sel_to) {
1331  copy_v3_v3(mirr->co, v->co);
1332  mirr->co[0] *= -1.0f;
1333  }
1334  }
1335  }
1336  }
1337 }
1338 
1341 /* -------------------------------------------------------------------- */
1346 {
1347  BMIter iter;
1348  BMElem *ele;
1349  int itermode;
1350  char hflag_swap = swap ? BM_ELEM_SELECT : 0;
1351  bool changed = true;
1352 
1353  if (em->selectmode & SCE_SELECT_VERTEX) {
1354  itermode = BM_VERTS_OF_MESH;
1355  }
1356  else if (em->selectmode & SCE_SELECT_EDGE) {
1357  itermode = BM_EDGES_OF_MESH;
1358  }
1359  else {
1360  itermode = BM_FACES_OF_MESH;
1361  }
1362 
1363  BM_ITER_MESH (ele, &iter, em->bm, itermode) {
1364  if (!BM_elem_flag_test(ele, BM_ELEM_HIDDEN)) {
1365  if (BM_elem_flag_test(ele, BM_ELEM_SELECT) ^ hflag_swap) {
1366  BM_elem_hide_set(em->bm, ele, true);
1367  changed = true;
1368  }
1369  }
1370  }
1371 
1372  if (changed) {
1374  }
1375  return changed;
1376 
1377  /* original hide flushing comment (OUTDATED):
1378  * hide happens on least dominant select mode, and flushes up, not down!
1379  * (helps preventing errors in subsurf) */
1380  /* - vertex hidden, always means edge is hidden too
1381  * - edge hidden, always means face is hidden too
1382  * - face hidden, only set face hide
1383  * - then only flush back down what's absolute hidden
1384  */
1385 }
1386 
1388 {
1389  const char iter_types[3] = {
1393  };
1394 
1395  const bool sels[3] = {
1396  (em->selectmode & SCE_SELECT_VERTEX) != 0,
1397  (em->selectmode & SCE_SELECT_EDGE) != 0,
1398  (em->selectmode & SCE_SELECT_FACE) != 0,
1399  };
1400  int i;
1401  bool changed = false;
1402 
1403  /* Use tag flag to remember what was hidden before all is revealed.
1404  * BM_ELEM_HIDDEN --> BM_ELEM_TAG */
1405  for (i = 0; i < 3; i++) {
1406  BMIter iter;
1407  BMElem *ele;
1408 
1409  BM_ITER_MESH (ele, &iter, em->bm, iter_types[i]) {
1410  if (BM_elem_flag_test(ele, BM_ELEM_HIDDEN)) {
1412  changed = true;
1413  }
1414  else {
1416  }
1417  }
1418  }
1419 
1420  if (!changed) {
1421  return false;
1422  }
1423 
1424  /* Reveal everything */
1426 
1427  /* Select relevant just-revealed elements */
1428  for (i = 0; i < 3; i++) {
1429  BMIter iter;
1430  BMElem *ele;
1431 
1432  if (!sels[i]) {
1433  continue;
1434  }
1435 
1436  BM_ITER_MESH (ele, &iter, em->bm, iter_types[i]) {
1437  if (BM_elem_flag_test(ele, BM_ELEM_TAG)) {
1438  BM_elem_select_set(em->bm, ele, select);
1439  }
1440  }
1441  }
1442 
1444 
1445  /* hidden faces can have invalid normals */
1447 
1448  return true;
1449 }
1450 
1453 /* -------------------------------------------------------------------- */
1458 {
1460 }
1461 
1463 {
1465  &(const struct BMeshNormalsUpdate_Params){
1466  .face_normals = true,
1467  });
1468 }
1469 
1471 {
1472  const char iter_types[3] = {
1476  };
1477 
1478  BMIter iter;
1479  BMElem *ele;
1480  int *tots[3];
1481  int i;
1482 
1483  tots[0] = &em->bm->totvertsel;
1484  tots[1] = &em->bm->totedgesel;
1485  tots[2] = &em->bm->totfacesel;
1486 
1487  em->bm->totvertsel = em->bm->totedgesel = em->bm->totfacesel = 0;
1488 
1489  for (i = 0; i < 3; i++) {
1490  ele = BM_iter_new(&iter, em->bm, iter_types[i], NULL);
1491  for (; ele; ele = BM_iter_step(&iter)) {
1492  if (BM_elem_flag_test(ele, BM_ELEM_SELECT)) {
1493  (*tots[i])++;
1494  }
1495  }
1496  }
1497 }
1498 
1500 {
1501  BMEditMesh *em = mesh->edit_mesh;
1502  /* Order of calling isn't important. */
1505 
1506  if (params->calc_normals && params->calc_looptri) {
1507  /* Calculating both has some performance gains. */
1509  }
1510  else {
1511  if (params->calc_normals) {
1513  }
1514 
1515  if (params->calc_looptri) {
1517  }
1518  }
1519 
1520  if (params->is_destructive) {
1521  /* TODO(campbell): we may be able to remove this now! */
1522  // BM_mesh_elem_table_free(em->bm, BM_ALL_NOLOOP);
1523  }
1524  else {
1525  /* in debug mode double check we didn't need to recalculate */
1526  BLI_assert(BM_mesh_elem_table_check(em->bm) == true);
1527  }
1528  if (em->bm->spacearr_dirty & BM_SPACEARR_BMO_SET) {
1529  BM_lnorspace_invalidate(em->bm, false);
1531  }
1532 
1533 #ifdef DEBUG
1534  {
1535  BMEditSelection *ese;
1536  for (ese = em->bm->selected.first; ese; ese = ese->next) {
1538  }
1539  }
1540 #endif
1541 }
1542 
1543 void EDBM_update_extern(struct Mesh *me, const bool do_tessellation, const bool is_destructive)
1544 {
1545  EDBM_update(me,
1546  &(const struct EDBMUpdate_Params){
1547  .calc_looptri = do_tessellation,
1548  .calc_normals = false,
1549  .is_destructive = is_destructive,
1550  });
1551 }
1552 
1555 /* -------------------------------------------------------------------- */
1560 {
1562  return 1;
1563  }
1564 
1565  return 0;
1566 }
1567 
1570 /* -------------------------------------------------------------------- */
1575 {
1576  BMElem *ele = NULL;
1577 
1578  if ((em->selectmode & SCE_SELECT_VERTEX) && eve) {
1579  ele = (BMElem *)eve;
1580  }
1581  else if ((em->selectmode & SCE_SELECT_EDGE) && eed) {
1582  ele = (BMElem *)eed;
1583  }
1584  else if ((em->selectmode & SCE_SELECT_FACE) && efa) {
1585  ele = (BMElem *)efa;
1586  }
1587 
1588  return ele;
1589 }
1590 
1592 {
1593  BMesh *bm = em->bm;
1594  int index = BM_elem_index_get(ele);
1595 
1596  if (ele->head.htype == BM_VERT) {
1598  }
1599  else if (ele->head.htype == BM_EDGE) {
1601  index += bm->totvert;
1602  }
1603  else if (ele->head.htype == BM_FACE) {
1605  index += bm->totvert + bm->totedge;
1606  }
1607  else {
1608  BLI_assert(0);
1609  }
1610 
1611  return index;
1612 }
1613 
1615 {
1616  BMesh *bm = em->bm;
1617 
1618  if (index < bm->totvert) {
1619  return (BMElem *)BM_vert_at_index_find_or_table(bm, index);
1620  }
1621  index -= bm->totvert;
1622  if (index < bm->totedge) {
1623  return (BMElem *)BM_edge_at_index_find_or_table(bm, index);
1624  }
1625  index -= bm->totedge;
1626  if (index < bm->totface) {
1627  return (BMElem *)BM_face_at_index_find_or_table(bm, index);
1628  }
1629 
1630  return NULL;
1631 }
1632 
1634  BMEditMesh *em,
1635  BMElem *ele,
1636  int *r_object_index)
1637 {
1638  uint bases_len;
1639  int elem_index = -1;
1640  *r_object_index = -1;
1641  Base **bases = BKE_view_layer_array_from_bases_in_edit_mode(view_layer, NULL, &bases_len);
1642  for (uint base_index = 0; base_index < bases_len; base_index++) {
1643  Base *base_iter = bases[base_index];
1644  if (BKE_editmesh_from_object(base_iter->object) == em) {
1645  *r_object_index = base_index;
1646  elem_index = EDBM_elem_to_index_any(em, ele);
1647  break;
1648  }
1649  }
1650  MEM_freeN(bases);
1651  return elem_index;
1652 }
1653 
1655  uint object_index,
1656  uint elem_index,
1657  Object **r_obedit)
1658 {
1659  uint bases_len;
1660  Base **bases = BKE_view_layer_array_from_bases_in_edit_mode(view_layer, NULL, &bases_len);
1661  *r_obedit = NULL;
1662  Object *obedit = (object_index < bases_len) ? bases[object_index]->object : NULL;
1663  MEM_freeN(bases);
1664  if (obedit != NULL) {
1665  BMEditMesh *em = BKE_editmesh_from_object(obedit);
1666  BMElem *ele = EDBM_elem_from_index_any(em, elem_index);
1667  if (ele != NULL) {
1668  *r_obedit = obedit;
1669  return ele;
1670  }
1671  }
1672  return NULL;
1673 }
1674 
1677 /* -------------------------------------------------------------------- */
1682  struct BMBVHTree *tree, const float co[3], const float dir[3], float *r_hitout, BMEdge *e)
1683 {
1684  BMFace *f = BKE_bmbvh_ray_cast(tree, co, dir, 0.0f, NULL, r_hitout, NULL);
1685 
1686  if (f && BM_edge_in_face(e, f)) {
1687  return NULL;
1688  }
1689 
1690  return f;
1691 }
1692 
1693 static void scale_point(float c1[3], const float p[3], const float s)
1694 {
1695  sub_v3_v3(c1, p);
1696  mul_v3_fl(c1, s);
1697  add_v3_v3(c1, p);
1698 }
1699 
1701  BMEdge *e,
1702  struct Depsgraph *depsgraph,
1703  ARegion *region,
1704  View3D *v3d,
1705  Object *obedit)
1706 {
1707  BMFace *f;
1708  float co1[3], co2[3], co3[3], dir1[3], dir2[3], dir3[3];
1709  float origin[3], invmat[4][4];
1710  float epsilon = 0.01f;
1711  float end[3];
1712  const float mval_f[2] = {
1713  region->winx / 2.0f,
1714  region->winy / 2.0f,
1715  };
1716 
1717  ED_view3d_win_to_segment_clipped(depsgraph, region, v3d, mval_f, origin, end, false);
1718 
1719  invert_m4_m4(invmat, obedit->obmat);
1720  mul_m4_v3(invmat, origin);
1721 
1722  copy_v3_v3(co1, e->v1->co);
1723  mid_v3_v3v3(co2, e->v1->co, e->v2->co);
1724  copy_v3_v3(co3, e->v2->co);
1725 
1726  scale_point(co1, co2, 0.99);
1727  scale_point(co3, co2, 0.99);
1728 
1729  /* OK, idea is to generate rays going from the camera origin to the
1730  * three points on the edge (v1, mid, v2). */
1731  sub_v3_v3v3(dir1, origin, co1);
1732  sub_v3_v3v3(dir2, origin, co2);
1733  sub_v3_v3v3(dir3, origin, co3);
1734 
1738 
1739  /* Offset coordinates slightly along view vectors,
1740  * to avoid hitting the faces that own the edge. */
1741  add_v3_v3v3(co1, co1, dir1);
1742  add_v3_v3v3(co2, co2, dir2);
1743  add_v3_v3v3(co3, co3, dir3);
1744 
1745  normalize_v3(dir1);
1746  normalize_v3(dir2);
1747  normalize_v3(dir3);
1748 
1749  /* do three samplings: left, middle, right */
1750  f = edge_ray_cast(tree, co1, dir1, NULL, e);
1751  if (f && !edge_ray_cast(tree, co2, dir2, NULL, e)) {
1752  return true;
1753  }
1754  if (f && !edge_ray_cast(tree, co3, dir3, NULL, e)) {
1755  return true;
1756  }
1757  if (!f) {
1758  return true;
1759  }
1760 
1761  return false;
1762 }
1763 
1766 /* -------------------------------------------------------------------- */
1771  bContext *C, Depsgraph *depsgraph, ARegion *region, Object *obedit, BMEditMesh *em)
1772 {
1773  BMIter iter;
1774  BMVert *eve;
1775 
1776  ED_view3d_init_mats_rv3d(obedit, region->regiondata);
1777 
1779  CTX_data_scene(C), 0);
1780 
1781  BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) {
1782  if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
1783  float mval[2], co_proj[3];
1785  V3D_PROJ_RET_OK) {
1787  snap_context,
1788  depsgraph,
1789  region,
1790  CTX_wm_view3d(C),
1792  &(const struct SnapObjectParams){
1793  .snap_target_select = SCE_SNAP_TARGET_NOT_ACTIVE,
1794  .edit_mode_type = SNAP_GEOM_FINAL,
1795  .use_occlusion_test = true,
1796  },
1797  NULL,
1798  mval,
1799  NULL,
1800  NULL,
1801  co_proj,
1802  NULL)) {
1803  mul_v3_m4v3(eve->co, obedit->imat, co_proj);
1804  }
1805  }
1806  }
1807  }
1808 
1810 }
1811 
typedef float(TangentPoint)[2]
struct Scene * CTX_data_scene(const bContext *C)
Definition: context.c:1090
struct Object * CTX_data_edit_object(const bContext *C)
Definition: context.c:1370
struct View3D * CTX_wm_view3d(const bContext *C)
Definition: context.c:784
CustomData interface, see also DNA_customdata_types.h.
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_data(BMEditMesh *em)
Definition: editmesh.c:181
void BKE_editmesh_looptri_calc(BMEditMesh *em)
Definition: editmesh.c:127
void BKE_editmesh_looptri_and_normals_calc(BMEditMesh *em)
Definition: editmesh.c:135
BMEditMesh * BKE_editmesh_create(BMesh *bm)
Definition: editmesh.c:29
BMEditMesh * BKE_editmesh_from_object(struct Object *ob)
Return the BMEditMesh for a given object.
Definition: editmesh.c:58
struct BMFace * BKE_bmbvh_ray_cast(BMBVHTree *tree, const float co[3], const float dir[3], float radius, float *r_dist, float r_hitout[3], float r_cagehit[3])
Definition: editmesh_bvh.c:290
#define BKE_view_layer_array_from_bases_in_edit_mode(view_layer, v3d, r_len)
Definition: BKE_layer.h:539
struct BMesh * BKE_mesh_to_bmesh(struct Mesh *me, struct Object *ob, bool add_key_index, const struct BMeshCreateParams *params)
Definition: mesh.cc:1150
void BKE_mesh_uv_vert_map_free(UvVertMap *vmap)
Definition: mesh_mapping.c:167
#define STD_UV_CONNECT_LIMIT
General operations, lookup, etc. for blender objects.
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
void BKE_report(ReportList *reports, eReportType type, const char *message)
Definition: report.c:83
#define BLI_array_alloca(arr, realsize)
Definition: BLI_alloca.h:22
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define BLI_buffer_reinit_data(buffer_, type_, new_count_)
Definition: BLI_buffer.h:47
@ BLI_BUFFER_NOP
Definition: BLI_buffer.h:21
#define BLI_buffer_declare_static(type_, name_, flag_, static_count_)
Definition: BLI_buffer.h:25
#define BLI_buffer_free(name_)
Definition: BLI_buffer.h:94
A KD-tree for nearest neighbor search.
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
Definition: BLI_listbase.h:269
MINLINE float square_f(float a)
float cross_poly_v2(const float verts[][2], unsigned int nr)
Definition: math_geom.c:141
bool invert_m4_m4(float R[4][4], const float A[4][4])
Definition: math_matrix.c:1287
void mul_m4_v3(const float M[4][4], float r[3])
Definition: math_matrix.c:729
void mul_v3_m4v3(float r[3], const float M[4][4], const float v[3])
Definition: math_matrix.c:739
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 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 bool compare_v2v2(const float a[2], const float b[2], float limit) ATTR_WARN_UNUSED_RESULT
MINLINE void add_v3_v3v3(float r[3], const float a[3], const float b[3])
void copy_vn_i(int *array_tar, int size, int val)
Definition: math_vector.c:1223
MINLINE float normalize_v3_length(float r[3], float unit_scale)
void mid_v3_v3v3(float r[3], const float a[3], const float b[3])
Definition: math_vector.c:237
MINLINE void add_v3_v3(float r[3], const float a[3])
unsigned int uint
Definition: BLI_sys_types.h:67
#define UNLIKELY(x)
#define LIKELY(x)
void swap(T &a, T &b)
Definition: Common.h:19
struct Depsgraph Depsgraph
Definition: DEG_depsgraph.h:35
void DEG_id_tag_update(struct ID *id, int flag)
@ ID_RECALC_GEOMETRY
Definition: DNA_ID.h:791
@ CD_FLAG_TEMPORARY
@ CD_PROP_BYTE_COLOR
@ CD_PROP_INT32
@ CD_MLOOPUV
Object is a sort of wrapper for general info.
#define UV_SELECT_EDGE
@ SCE_SNAP_TARGET_NOT_ACTIVE
#define SCE_SELECT_FACE
#define UV_SYNC_SELECTION
#define SCE_SELECT_VERTEX
#define SCE_SELECT_EDGE
@ SCE_SNAP_MODE_FACE_RAYCAST
void ED_mesh_mirror_topo_table_end(struct Object *ob)
void ED_mesh_mirrtopo_free(MirrTopoStore_t *mesh_topo_store)
void ED_mesh_mirror_spatial_table_end(struct Object *ob)
void ED_mesh_mirrtopo_init(struct BMEditMesh *em, struct Mesh *me, MirrTopoStore_t *mesh_topo_store, bool skip_em_vert_array_init)
bool ED_operator_view3d_active(struct bContext *C)
Definition: screen_ops.c:225
bool ED_operator_editmesh(struct bContext *C)
Definition: screen_ops.c:433
eSnapMode ED_transform_snap_object_project_view3d(struct SnapObjectContext *sctx, struct Depsgraph *depsgraph, const ARegion *region, const View3D *v3d, const eSnapMode snap_to, const struct SnapObjectParams *params, const float init_co[3], const float mval[2], const float prev_co[3], float *dist_px, float r_loc[3], float r_no[3])
SnapObjectContext * ED_transform_snap_object_context_create(struct Scene *scene, int flag)
void ED_transform_snap_object_context_destroy(SnapObjectContext *sctx)
bool uvedit_uv_select_test(const struct Scene *scene, struct BMLoop *l, int cd_loop_uv_offset)
bool uvedit_edge_select_test(const struct Scene *scene, struct BMLoop *l, int cd_loop_uv_offset)
bool ED_view3d_win_to_segment_clipped(const struct Depsgraph *depsgraph, const struct ARegion *region, const struct View3D *v3d, const float mval[2], float r_ray_start[3], float r_ray_end[3], bool do_clip_planes)
@ V3D_PROJ_TEST_NOP
Definition: ED_view3d.h:234
@ V3D_PROJ_RET_OK
Definition: ED_view3d.h:217
eV3DProjStatus ED_view3d_project_float_object(const struct ARegion *region, const float co[3], float r_co[2], eV3DProjTest flag)
void ED_view3d_init_mats_rv3d(const struct Object *ob, struct RegionView3D *rv3d)
Definition: space_view3d.c:166
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
#define C
Definition: RandGen.cpp:25
#define NC_GEOM
Definition: WM_types.h:343
#define ND_DATA
Definition: WM_types.h:456
#define NC_SCENE
Definition: WM_types.h:328
#define ND_TOOLSETTINGS
Definition: WM_types.h:397
__forceinline const avxb select(const avxb &m, const avxb &t, const avxb &f)
Definition: avxb.h:154
@ BM_SPACEARR_BMO_SET
Definition: bmesh_class.h:417
#define BM_DEFAULT_NGON_STACK_SIZE
Definition: bmesh_class.h:640
#define BM_ALL_NOLOOP
Definition: bmesh_class.h:411
#define BM_FACE_FIRST_LOOP(p)
Definition: bmesh_class.h:622
@ 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_ELEM_CD_GET_VOID_P(ele, offset)
Definition: bmesh_class.h:541
BMesh * BM_mesh_copy(BMesh *bm_old)
eBMOpErrorLevel
Definition: bmesh_error.h:16
@ BMO_ERROR_WARN
Definition: bmesh_error.h:27
@ BMO_ERROR_FATAL
Definition: bmesh_error.h:34
@ BMO_ERROR_CANCEL
Definition: bmesh_error.h:21
bool BMO_error_pop(BMesh *bm, const char **r_msg, BMOperator **r_op, eBMOpErrorLevel *r_level)
#define BM_elem_index_get(ele)
Definition: bmesh_inline.h:110
#define BM_elem_flag_disable(ele, hflag)
Definition: bmesh_inline.h:15
#define BM_elem_flag_test(ele, hflag)
Definition: bmesh_inline.h:12
#define BM_elem_flag_enable(ele, hflag)
Definition: bmesh_inline.h:14
void BM_data_layer_add_named(BMesh *bm, CustomData *data, int type, const char *name)
Definition: bmesh_interp.c:857
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_flush_ex(BMesh *bm, const short selectmode, eBMSelectionFlushFLags flags)
Select Mode Flush.
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)
#define BM_elem_hide_set(bm, ele, hide)
Definition: bmesh_marking.h:27
@ BM_SELECT_LEN_FLUSH_RECALC_ALL
Definition: bmesh_marking.h:20
void BM_mesh_data_free(BMesh *bm)
BMesh Free Mesh Data.
Definition: bmesh_mesh.cc:146
void BM_mesh_clear(BMesh *bm)
BMesh Clear Mesh.
Definition: bmesh_mesh.cc:237
BMEdge * BM_edge_at_index_find_or_table(BMesh *bm, const int index)
Definition: bmesh_mesh.cc:692
BMFace * BM_face_at_index_find_or_table(BMesh *bm, const int index)
Definition: bmesh_mesh.cc:700
BMVert * BM_vert_at_index_find_or_table(BMesh *bm, const int index)
Definition: bmesh_mesh.cc:684
void BM_mesh_elem_table_ensure(BMesh *bm, const char htype)
Definition: bmesh_mesh.cc:558
void BM_mesh_elem_index_ensure(BMesh *bm, const char htype)
Definition: bmesh_mesh.cc:446
bool BM_mesh_elem_table_check(BMesh *bm)
Definition: bmesh_mesh.cc:524
BLI_INLINE BMFace * BM_face_at_index(BMesh *bm, const int index)
Definition: bmesh_mesh.h:115
BLI_INLINE BMVert * BM_vert_at_index(BMesh *bm, const int index)
Definition: bmesh_mesh.h:103
void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMeshParams *params)
void BM_mesh_normals_update_ex(BMesh *bm, const struct BMeshNormalsUpdate_Params *params)
BMesh Compute Normals.
void BM_lnorspace_invalidate(BMesh *bm, const bool do_invalidate_all)
bool BMO_op_vinitf(BMesh *bm, BMOperator *op, int flag, const char *fmt, va_list vlist)
void BMO_slot_buffer_hflag_enable(BMesh *bm, BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name, char htype, char hflag, 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, char htype, char hflag, 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, 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
ATTR_WARN_UNUSED_RESULT const void * element
BMEdge * BM_edge_exists(BMVert *v_a, BMVert *v_b)
Definition: bmesh_query.c:1553
bool BM_edge_in_face(const BMEdge *e, const BMFace *f)
Definition: bmesh_query.c:420
BMFace * BM_face_exists(BMVert **varr, int len)
Definition: bmesh_query.c:1612
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)
#define INVALID_ISLAND
UvMapVert * BM_uv_vert_map_at_index(UvVertMap *vmap, uint v)
void EDBM_select_more(BMEditMesh *em, const bool use_face_step)
bool EDBM_op_callf(BMEditMesh *em, wmOperator *op, const char *fmt,...)
BMElem * EDBM_elem_from_selectmode(BMEditMesh *em, BMVert *eve, BMEdge *eed, BMFace *efa)
static void bm_uv_assign_island(UvElementMap *element_map, UvElement *element, int nisland, uint *map, UvElement *islandbuf, int islandbufsize)
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_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)
BMElem * EDBM_elem_from_index_any(BMEditMesh *em, uint index)
bool EDBM_uv_check(BMEditMesh *em)
void BM_uv_element_map_free(UvElementMap *element_map)
void EDBM_stats_update(BMEditMesh *em)
BMElem * EDBM_elem_from_index_any_multi(ViewLayer *view_layer, uint object_index, uint elem_index, Object **r_obedit)
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)
UvElementMap * BM_uv_element_map_create(BMesh *bm, const Scene *scene, const bool uv_selected, const bool use_winding, const bool do_islands)
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_mesh_free_data(BMEditMesh *em)
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)
void EDBM_update_extern(struct Mesh *me, const bool do_tessellation, const bool is_destructive)
#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_redo_state_restore(BMBackup *backup, BMEditMesh *em, bool recalc_looptri)
void EDBM_select_less(BMEditMesh *em, const bool use_face_step)
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_normals_update_ex(BMEditMesh *em, const struct BMeshNormalsUpdate_Params *params)
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_restore_and_free(BMBackup *backup, BMEditMesh *em, bool recalc_looptri)
void EDBM_verts_mirror_apply(BMEditMesh *em, const int sel_from, const int sel_to)
void BM_uv_vert_map_free(UvVertMap *vmap)
void EDBM_update(Mesh *mesh, const struct EDBMUpdate_Params *params)
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)
static int bm_uv_edge_select_build_islands(UvElementMap *element_map, const Scene *scene, UvElement *islandbuf, uint *map, bool uv_selected, int cd_loop_uv_offset)
void EDBM_redo_state_free(BMBackup *backup)
void * tree
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:33
static ulong * next
static MirrTopoStore_t mesh_topo_store
Definition: meshtools.cc:838
static unsigned a[3]
Definition: RandGen.cpp:78
SymEdge< T > * prev(const SymEdge< T > *se)
Definition: delaunay_2d.cc:105
static double epsilon
SocketIndexByIdentifierMap * map
_W64 int intptr_t
Definition: stdint.h:118
void * regiondata
short selectmode
Definition: BKE_editmesh.h:52
struct BMLoop *(* looptris)[3]
Definition: BKE_editmesh.h:48
struct BMesh * bm
Definition: BKE_editmesh.h:40
short mat_nr
Definition: BKE_editmesh.h:54
int mirror_cdlayer
Definition: BKE_editmesh.h:57
struct BMEditSelection * next
Definition: bmesh_marking.h:10
BMHeader head
Definition: bmesh_class.h:243
int len
Definition: bmesh_class.h:267
char htype
Definition: bmesh_class.h:64
void * data
Definition: bmesh_class.h:51
struct BMVert * v
Definition: bmesh_class.h:153
struct BMFace * f
Definition: bmesh_class.h:171
struct BMLoop * next
Definition: bmesh_class.h:233
eBMOpSlotSubType_Union slot_subtype
struct BMOpSlot slots_out[BMO_OP_MAX_SLOTS]
float co[3]
Definition: bmesh_class.h:87
BMHeader head
Definition: bmesh_class.h:85
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
int totloop
Definition: bmesh_class.h:297
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
ListBase block
Definition: DNA_key_types.h:84
void * first
Definition: DNA_listBase.h:31
Definition: BKE_main.h:121
struct BMEditMesh * edit_mesh
struct Key * key
intptr_t * index_lookup
Definition: ED_mesh.h:432
float imat[4][4]
short shapenr
float obmat[4][4]
void * data
struct ToolSettings * toolsettings
struct UvElement * buf
struct UvElement ** vert
unsigned char flag
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
void WM_main_add_notifier(unsigned int type, void *reference)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)