Blender  V3.3
transform_convert_mesh.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2001-2002 NaN Holding BV. All rights reserved. */
3 
8 #include "DNA_mesh_types.h"
9 #include "DNA_meshdata_types.h"
10 
11 #include "MEM_guardedalloc.h"
12 
13 #include "BLI_alloca.h"
14 #include "BLI_bitmap.h"
15 #include "BLI_linklist_stack.h"
16 #include "BLI_math.h"
17 #include "BLI_memarena.h"
18 
19 #include "BKE_context.h"
20 #include "BKE_crazyspace.h"
21 #include "BKE_editmesh.h"
22 #include "BKE_mesh.h"
23 #include "BKE_modifier.h"
24 #include "BKE_scene.h"
25 
26 #include "ED_mesh.h"
27 
28 #include "DEG_depsgraph_query.h"
29 
30 #include "transform.h"
31 #include "transform_orientations.h"
32 #include "transform_snap.h"
33 
34 #include "transform_convert.h"
35 
36 /* -------------------------------------------------------------------- */
41  struct TransDataContainer *tc,
42  struct TransCustomData *custom_data);
43 
46 
49 
51  float prop_size;
54 };
55 
76 };
77 
78 #define PARTIAL_TYPE_MAX 2
79 
87 };
88 
93 };
94 
96 {
97  struct TransCustomDataMesh *tcmd = tc->custom.type.data;
98  BLI_assert(tc->custom.type.data == NULL ||
100  if (tc->custom.type.data == NULL) {
101  tc->custom.type.data = MEM_callocN(sizeof(struct TransCustomDataMesh), __func__);
103  tcmd = tc->custom.type.data;
106  }
107  return tcmd;
108 }
109 
111 {
112  if (tcmd->cd_layer_correct != NULL) {
114  }
115 
116  for (int i = 0; i < ARRAY_SIZE(tcmd->partial_update); i++) {
117  if (tcmd->partial_update[i].cache != NULL) {
119  }
120  }
121 
122  MEM_freeN(tcmd);
123 }
124 
126  struct TransDataContainer *UNUSED(tc),
127  struct TransCustomData *custom_data)
128 {
129  struct TransCustomDataMesh *tcmd = custom_data->data;
131  custom_data->data = NULL;
132 }
133 
136 /* -------------------------------------------------------------------- */
143 };
144 
147  struct MemArena *arena;
148 
149  struct GHash *origfaces;
151 
152  /* Special handle for multi-resolution. */
154 
155  /* Optionally merge custom-data groups (this keeps UVs connected for example). */
156  struct {
158  struct GHash *origverts;
160  int data_len;
167 
169 };
170 
171 #define USE_FACE_SUBSTITUTE
172 #ifdef USE_FACE_SUBSTITUTE
173 # define FACE_SUBSTITUTE_INDEX INT_MIN
174 
180 {
181  BMFace *best_face = NULL;
182  BMLoop *l;
183  BMIter liter;
184  BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
185  BMLoop *l_radial_next = l->radial_next;
186  BMFace *f_test = l_radial_next->f;
187  if (f_test == f) {
188  continue;
189  }
190  if (is_zero_v3(f_test->no)) {
191  continue;
192  }
193 
194  /* Check the loops edge isn't selected. */
195  if (!BM_elem_flag_test(l_radial_next->v, BM_ELEM_SELECT) &&
196  !BM_elem_flag_test(l_radial_next->next->v, BM_ELEM_SELECT)) {
197  /* Prefer edges with unselected vertices.
198  * Useful for extrude. */
199  best_face = f_test;
200  break;
201  }
202  if (best_face == NULL) {
203  best_face = f_test;
204  }
205  }
206  return best_face;
207 }
208 
210  BMFace *f,
211  BMFace *f_copy)
212 {
213  BLI_assert(is_zero_v3(f->no));
214  BMesh *bm = tcld->bm;
215  /* It is impossible to calculate the loops weights of a face without area.
216  * Find a substitute. */
218  if (f_substitute) {
219  /* Copy the custom-data from the substitute face. */
220  BMLoop *l_iter, *l_first;
221  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
222  do {
223  BM_loop_interp_from_face(bm, l_iter, f_substitute, false, false);
224  } while ((l_iter = l_iter->next) != l_first);
225 
226  /* Use the substitute face as the reference during the transformation. */
227  BMFace *f_substitute_copy = BM_face_copy(tcld->bm_origfaces, bm, f_substitute, true, true);
228 
229  /* Hack: reference substitute face in `f_copy->no`.
230  * `tcld->origfaces` is already used to restore the initial value. */
232  *((BMFace **)&f_copy->no[0]) = f_substitute_copy;
233  }
234 }
235 
237 {
239  return *((BMFace **)&f_copy->no[0]);
240 }
241 
242 #endif /* USE_FACE_SUBSTITUTE */
243 
245  struct TransDataBasic *td,
246  const int index)
247 {
248  BMesh *bm = tcld->bm;
249  BMVert *v = td->extra;
250  BMIter liter;
251  int j, l_num;
252  float *loop_weights;
253 
254  // BM_ITER_ELEM (l, &liter, sv->v, BM_LOOPS_OF_VERT) {
255  BM_iter_init(&liter, bm, BM_LOOPS_OF_VERT, v);
256  l_num = liter.count;
257  loop_weights = tcld->use_merge_group ? BLI_array_alloca(loop_weights, l_num) : NULL;
258  for (j = 0; j < l_num; j++) {
259  BMLoop *l = BM_iter_step(&liter);
260  BMLoop *l_prev, *l_next;
261 
262  /* Generic custom-data correction. Copy face data. */
263  void **val_p;
264  if (!BLI_ghash_ensure_p(tcld->origfaces, l->f, &val_p)) {
265  BMFace *f_copy = BM_face_copy(tcld->bm_origfaces, bm, l->f, true, true);
266  *val_p = f_copy;
267 #ifdef USE_FACE_SUBSTITUTE
268  if (is_zero_v3(l->f->no)) {
270  }
271 #endif
272  }
273 
274  if (tcld->use_merge_group) {
275  if ((l_prev = BM_loop_find_prev_nodouble(l, l->next, FLT_EPSILON)) &&
276  (l_next = BM_loop_find_next_nodouble(l, l_prev, FLT_EPSILON))) {
277  loop_weights[j] = angle_v3v3v3(l_prev->v->co, l->v->co, l_next->v->co);
278  }
279  else {
280  loop_weights[j] = 0.0f;
281  }
282  }
283  }
284 
285  if (tcld->use_merge_group) {
286  /* Store cd_loop_groups. */
287  struct TransCustomDataMergeGroup *merge_data = &tcld->merge_group.data[index];
288  if (l_num != 0) {
289  merge_data->cd_loop_groups = BLI_memarena_alloc(
290  tcld->arena, tcld->merge_group.customdatalayer_map_len * sizeof(void *));
291  for (j = 0; j < tcld->merge_group.customdatalayer_map_len; j++) {
292  const int layer_nr = tcld->merge_group.customdatalayer_map[j];
294  bm, v, layer_nr, loop_weights, tcld->arena);
295  }
296  }
297  else {
298  merge_data->cd_loop_groups = NULL;
299  }
300 
302  }
303 }
304 
306  struct TransCustomDataLayer *tcld)
307 {
308  BMesh *bm = tcld->bm;
309 
310  struct GHash *origfaces = BLI_ghash_ptr_new(__func__);
311  struct BMesh *bm_origfaces = BM_mesh_create(&bm_mesh_allocsize_default,
312  &((struct BMeshCreateParams){
313  .use_toolflags = false,
314  }));
315 
316  /* We need to have matching loop custom-data. */
318 
319  tcld->origfaces = origfaces;
320  tcld->bm_origfaces = bm_origfaces;
321 
324 }
325 
327  struct TransCustomDataLayer *tcld)
328 {
329  BMesh *bm = tcld->bm;
331 
332  /* TODO: We don't need `layer_math_map` when there are no loops linked
333  * to one of the sliding vertices. */
334 
335  /* Over allocate, only 'math' layers are indexed. */
336  int *customdatalayer_map = MEM_mallocN(sizeof(int) * bm->ldata.totlayer, __func__);
337  int layer_math_map_len = 0;
338  for (int i = 0; i < bm->ldata.totlayer; i++) {
339  if (CustomData_layer_has_math(&bm->ldata, i)) {
340  customdatalayer_map[layer_math_map_len++] = i;
341  }
342  }
343  BLI_assert(layer_math_map_len != 0);
344 
345  tcld->merge_group.data_len = tc->data_len + tc->data_mirror_len;
346  tcld->merge_group.customdatalayer_map = customdatalayer_map;
347  tcld->merge_group.customdatalayer_map_len = layer_math_map_len;
350  tcld->arena, tcld->merge_group.data_len * sizeof(*tcld->merge_group.data));
351 }
352 
354  TransDataContainer *tc, const bool use_merge_group)
355 {
357  BMesh *bm = em->bm;
358 
359  if (bm->shapenr > 1) {
360  /* Don't do this at all for non-basis shape keys, too easy to
361  * accidentally break uv maps or vertex colors then */
362  /* create copies of faces for custom-data projection. */
363  return NULL;
364  }
366  /* There is no custom-data to correct. */
367  return NULL;
368  }
369 
370  struct TransCustomDataLayer *tcld = MEM_callocN(sizeof(*tcld), __func__);
371  tcld->bm = bm;
373 
374  /* Init `cd_loop_mdisp_offset` to -1 to avoid problems with a valid index. */
375  tcld->cd_loop_mdisp_offset = -1;
377 
379 
380  if (tcld->use_merge_group) {
382  }
383 
384  {
385  /* Setup Verts. */
386  int i = 0;
387 
388  TransData *tob = tc->data;
389  for (int j = tc->data_len; j--; tob++, i++) {
391  }
392 
393  TransDataMirror *td_mirror = tc->data_mirror;
394  for (int j = tc->data_mirror_len; j--; td_mirror++, i++) {
396  }
397  }
398 
399  return tcld;
400 }
401 
403 {
404  struct TransCustomDataLayer *customdatacorrect;
406 
407  if (!customdatacorrect) {
408  return;
409  }
410 
412  BLI_assert(tcmd->cd_layer_correct == NULL);
413  tcmd->cd_layer_correct = customdatacorrect;
414 }
415 
417 {
419 
420  if (tcld->bm_origfaces) {
421  BM_mesh_free(tcld->bm_origfaces);
422  }
423  if (tcld->origfaces) {
425  }
426  if (tcld->merge_group.origverts) {
428  }
429  if (tcld->arena) {
430  BLI_memarena_free(tcld->arena);
431  }
432  if (tcld->merge_group.customdatalayer_map) {
434  }
435 
436  MEM_freeN(tcld);
437 }
438 
440 {
441  bool use_merge_group = false;
442  if (ELEM(t->mode, TFM_EDGE_SLIDE, TFM_VERT_SLIDE)) {
443  if (!(t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT_SLIDE)) {
444  /* No custom-data correction. */
445  return;
446  }
447  use_merge_group = true;
448  }
449  else if (ELEM(t->mode,
451  TFM_ROTATION,
452  TFM_RESIZE,
453  TFM_TOSPHERE,
454  TFM_SHEAR,
455  TFM_BEND,
458  TFM_PUSHPULL,
459  TFM_ALIGN)) {
460  {
461  if (!(t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT)) {
462  /* No custom-data correction. */
463  return;
464  }
465  use_merge_group = (t->settings->uvcalc_flag & UVCALC_TRANSFORM_CORRECT_KEEP_CONNECTED) != 0;
466  }
467  }
468  else {
469  return;
470  }
471 
473  if (tc->custom.type.data != NULL) {
474  struct TransCustomDataMesh *tcmd = tc->custom.type.data;
475  if (tcmd && tcmd->cd_layer_correct) {
477  tcmd->cd_layer_correct = NULL;
478  }
479  }
480 
481  tc_mesh_customdatacorrect_create(tc, use_merge_group);
482  }
483 }
484 
487 /* -------------------------------------------------------------------- */
494 static const float *tc_mesh_vert_orig_co_get(struct TransCustomDataLayer *tcld, BMVert *v)
495 {
497  return td ? td->iloc : v->co;
498 }
499 
501  struct TransDataBasic *td,
502  struct TransCustomDataMergeGroup *merge_data,
503  bool do_loop_mdisps)
504 {
505  BMesh *bm = tcld->bm;
506  BMVert *v = td->extra;
507  const float *co_orig_3d = td->iloc;
508 
509  BMIter liter;
510  int j, l_num;
511  float *loop_weights;
512  const bool is_moved = (len_squared_v3v3(v->co, co_orig_3d) > FLT_EPSILON);
513  const bool do_loop_weight = is_moved && tcld->merge_group.customdatalayer_map_len;
514  const float *v_proj_axis = v->no;
515  /* original (l->prev, l, l->next) projections for each loop ('l' remains unchanged) */
516  float v_proj[3][3];
517 
518  if (do_loop_weight) {
519  project_plane_normalized_v3_v3v3(v_proj[1], co_orig_3d, v_proj_axis);
520  }
521 
522  // BM_ITER_ELEM (l, &liter, sv->v, BM_LOOPS_OF_VERT)
523  BM_iter_init(&liter, bm, BM_LOOPS_OF_VERT, v);
524  l_num = liter.count;
525  loop_weights = do_loop_weight ? BLI_array_alloca(loop_weights, l_num) : NULL;
526  for (j = 0; j < l_num; j++) {
527  BMFace *f_copy; /* the copy of 'f' */
528  BMLoop *l = BM_iter_step(&liter);
529 
530  f_copy = BLI_ghash_lookup(tcld->origfaces, l->f);
531 
532 #ifdef USE_FACE_SUBSTITUTE
533  /* In some faces it is not possible to calculate interpolation,
534  * so we use a substitute. */
535  if (BM_elem_index_get(f_copy) == FACE_SUBSTITUTE_INDEX) {
537  }
538 #endif
539 
540  /* only loop data, no vertex data since that contains shape keys,
541  * and we do not want to mess up other shape keys */
542  BM_loop_interp_from_face(bm, l, f_copy, false, false);
543 
544  /* weight the loop */
545  if (do_loop_weight) {
546  const float eps = 1.0e-8f;
547  const BMLoop *l_prev = l->prev;
548  const BMLoop *l_next = l->next;
549  const float *co_prev = tc_mesh_vert_orig_co_get(tcld, l_prev->v);
550  const float *co_next = tc_mesh_vert_orig_co_get(tcld, l_next->v);
551  bool co_prev_ok;
552  bool co_next_ok;
553 
554  /* In the unlikely case that we're next to a zero length edge -
555  * walk around the to the next.
556  *
557  * Since we only need to check if the vertex is in this corner,
558  * its not important _which_ loop - as long as its not overlapping
559  * 'sv->co_orig_3d', see: T45096. */
560  project_plane_normalized_v3_v3v3(v_proj[0], co_prev, v_proj_axis);
561  while (UNLIKELY(((co_prev_ok = (len_squared_v3v3(v_proj[1], v_proj[0]) > eps)) == false) &&
562  ((l_prev = l_prev->prev) != l->next))) {
563  co_prev = tc_mesh_vert_orig_co_get(tcld, l_prev->v);
564  project_plane_normalized_v3_v3v3(v_proj[0], co_prev, v_proj_axis);
565  }
566  project_plane_normalized_v3_v3v3(v_proj[2], co_next, v_proj_axis);
567  while (UNLIKELY(((co_next_ok = (len_squared_v3v3(v_proj[1], v_proj[2]) > eps)) == false) &&
568  ((l_next = l_next->next) != l->prev))) {
569  co_next = tc_mesh_vert_orig_co_get(tcld, l_next->v);
570  project_plane_normalized_v3_v3v3(v_proj[2], co_next, v_proj_axis);
571  }
572 
573  if (co_prev_ok && co_next_ok) {
574  const float dist = dist_signed_squared_to_corner_v3v3v3(
575  v->co, UNPACK3(v_proj), v_proj_axis);
576 
577  loop_weights[j] = (dist >= 0.0f) ? 1.0f : ((dist <= -eps) ? 0.0f : (1.0f + (dist / eps)));
578  if (UNLIKELY(!isfinite(loop_weights[j]))) {
579  loop_weights[j] = 0.0f;
580  }
581  }
582  else {
583  loop_weights[j] = 0.0f;
584  }
585  }
586  }
587 
588  if (tcld->use_merge_group) {
589  struct LinkNode **cd_loop_groups = merge_data->cd_loop_groups;
590  if (tcld->merge_group.customdatalayer_map_len && cd_loop_groups) {
591  if (do_loop_weight) {
592  for (j = 0; j < tcld->merge_group.customdatalayer_map_len; j++) {
594  bm, cd_loop_groups[j], tcld->merge_group.customdatalayer_map[j], loop_weights);
595  }
596  }
597  else {
598  for (j = 0; j < tcld->merge_group.customdatalayer_map_len; j++) {
600  bm, cd_loop_groups[j], tcld->merge_group.customdatalayer_map[j]);
601  }
602  }
603  }
604  }
605 
606  /* Special handling for multires
607  *
608  * Interpolate from every other loop (not ideal)
609  * However values will only be taken from loops which overlap other mdisps.
610  */
611  const bool update_loop_mdisps = is_moved && do_loop_mdisps && (tcld->cd_loop_mdisp_offset != -1);
612  if (update_loop_mdisps) {
613  float(*faces_center)[3] = BLI_array_alloca(faces_center, l_num);
614  BMLoop *l;
615 
616  BM_ITER_ELEM_INDEX (l, &liter, v, BM_LOOPS_OF_VERT, j) {
617  BM_face_calc_center_median(l->f, faces_center[j]);
618  }
619 
620  BM_ITER_ELEM_INDEX (l, &liter, v, BM_LOOPS_OF_VERT, j) {
621  BMFace *f_copy = BLI_ghash_lookup(tcld->origfaces, l->f);
622  float f_copy_center[3];
623  BMIter liter_other;
624  BMLoop *l_other;
625  int j_other;
626 
627  BM_face_calc_center_median(f_copy, f_copy_center);
628 
629  BM_ITER_ELEM_INDEX (l_other, &liter_other, v, BM_LOOPS_OF_VERT, j_other) {
631  l_other->f,
632  f_copy,
633  faces_center[j_other],
634  f_copy_center,
635  tcld->cd_loop_mdisp_offset);
636  }
637  }
638  }
639 }
640 
642 {
643  struct TransCustomDataMesh *tcmd = tc->custom.type.data;
644  struct TransCustomDataLayer *tcld = tcmd ? tcmd->cd_layer_correct : NULL;
645  if (tcld == NULL) {
646  return;
647  }
648  const bool use_merge_group = tcld->use_merge_group;
649 
650  struct TransCustomDataMergeGroup *merge_data = tcld->merge_group.data;
651  TransData *tob = tc->data;
652  for (int i = tc->data_len; i--; tob++) {
653  tc_mesh_customdatacorrect_apply_vert(tcld, (TransDataBasic *)tob, merge_data, is_final);
654 
655  if (use_merge_group) {
656  merge_data++;
657  }
658  }
659 
660  TransDataMirror *td_mirror = tc->data_mirror;
661  for (int i = tc->data_mirror_len; i--; td_mirror++) {
662  tc_mesh_customdatacorrect_apply_vert(tcld, (TransDataBasic *)td_mirror, merge_data, is_final);
663 
664  if (use_merge_group) {
665  merge_data++;
666  }
667  }
668 }
669 
672 /* -------------------------------------------------------------------- */
677 {
679  struct TransCustomDataMesh *tcmd = tc->custom.type.data;
680  struct TransCustomDataLayer *tcld = tcmd ? tcmd->cd_layer_correct : NULL;
681  if (!tcld) {
682  continue;
683  }
684 
685  BMesh *bm = tcld->bm;
686  BMesh *bm_copy = tcld->bm_origfaces;
687 
688  GHashIterator gh_iter;
689  GHASH_ITER (gh_iter, tcld->origfaces) {
690  BMFace *f = BLI_ghashIterator_getKey(&gh_iter);
691  BMFace *f_copy = BLI_ghashIterator_getValue(&gh_iter);
692  BLI_assert(f->len == f_copy->len);
693 
694  BMLoop *l_iter, *l_first, *l_copy;
695  l_iter = l_first = BM_FACE_FIRST_LOOP(f);
696  l_copy = BM_FACE_FIRST_LOOP(f_copy);
697  do {
698  /* TODO: Restore only the elements that transform. */
699  BM_elem_attrs_copy(bm_copy, bm, l_copy, l_iter);
700  l_copy = l_copy->next;
701  } while ((l_iter = l_iter->next) != l_first);
702  }
703  }
704 }
705 
708 /* -------------------------------------------------------------------- */
713  const bool calc_single_islands,
714  const bool calc_island_center,
715  const bool calc_island_axismtx,
716  struct TransIslandData *r_island_data)
717 {
718  struct TransIslandData data = {NULL};
719 
720  BMesh *bm = em->bm;
721  char htype;
722  char itype;
723  int i;
724 
725  /* group vars */
726  int *groups_array = NULL;
727  int(*group_index)[2] = NULL;
728 
729  bool has_only_single_islands = bm->totedgesel == 0 && bm->totfacesel == 0;
730  if (has_only_single_islands && !calc_single_islands) {
731  return;
732  }
733 
734  data.island_vert_map = MEM_mallocN(sizeof(*data.island_vert_map) * bm->totvert, __func__);
735  /* we shouldn't need this, but with incorrect selection flushing
736  * its possible we have a selected vertex that's not in a face,
737  * for now best not crash in that case. */
738  copy_vn_i(data.island_vert_map, bm->totvert, -1);
739 
740  if (!has_only_single_islands) {
742  groups_array = MEM_mallocN(sizeof(*groups_array) * bm->totedgesel, __func__);
743  data.island_tot = BM_mesh_calc_edge_groups(
744  bm, groups_array, &group_index, NULL, NULL, BM_ELEM_SELECT);
745 
746  htype = BM_EDGE;
748  }
749  else { /* (bm->selectmode & SCE_SELECT_FACE) */
750  groups_array = MEM_mallocN(sizeof(*groups_array) * bm->totfacesel, __func__);
751  data.island_tot = BM_mesh_calc_face_groups(
752  bm, groups_array, &group_index, NULL, NULL, NULL, BM_ELEM_SELECT, BM_VERT);
753 
754  htype = BM_FACE;
756  }
757 
758  BLI_assert(data.island_tot);
759  if (calc_island_center) {
760  data.center = MEM_mallocN(sizeof(*data.center) * data.island_tot, __func__);
761  }
762 
763  if (calc_island_axismtx) {
764  data.axismtx = MEM_mallocN(sizeof(*data.axismtx) * data.island_tot, __func__);
765  }
766 
768 
769  void **ele_array;
770  ele_array = (htype == BM_FACE) ? (void **)bm->ftable : (void **)bm->etable;
771 
773 
774  /* may be an edge OR a face array */
775  for (i = 0; i < data.island_tot; i++) {
776  BMEditSelection ese = {NULL};
777 
778  const int fg_sta = group_index[i][0];
779  const int fg_len = group_index[i][1];
780  float co[3], no[3], tangent[3];
781  int j;
782 
783  zero_v3(co);
784  zero_v3(no);
785  zero_v3(tangent);
786 
787  ese.htype = htype;
788 
789  /* loop on each face or edge in this group:
790  * - assign r_vert_map
791  * - calculate (co, no)
792  */
793  for (j = 0; j < fg_len; j++) {
794  ese.ele = ele_array[groups_array[fg_sta + j]];
795 
796  if (data.center) {
797  float tmp_co[3];
798  BM_editselection_center(&ese, tmp_co);
799  add_v3_v3(co, tmp_co);
800  }
801 
802  if (data.axismtx) {
803  float tmp_no[3], tmp_tangent[3];
804  BM_editselection_normal(&ese, tmp_no);
805  BM_editselection_plane(&ese, tmp_tangent);
806  add_v3_v3(no, tmp_no);
807  add_v3_v3(tangent, tmp_tangent);
808  }
809 
810  {
811  /* setup vertex map */
812  BMIter iter;
813  BMVert *v;
814 
815  /* connected edge-verts */
816  BM_ITER_ELEM (v, &iter, ese.ele, itype) {
817  data.island_vert_map[BM_elem_index_get(v)] = i;
818  }
819  }
820  }
821 
822  if (data.center) {
823  mul_v3_v3fl(data.center[i], co, 1.0f / (float)fg_len);
824  }
825 
826  if (data.axismtx) {
827  if (createSpaceNormalTangent(data.axismtx[i], no, tangent)) {
828  /* pass */
829  }
830  else {
831  if (normalize_v3(no) != 0.0f) {
832  axis_dominant_v3_to_m3(data.axismtx[i], no);
833  invert_m3(data.axismtx[i]);
834  }
835  else {
836  unit_m3(data.axismtx[i]);
837  }
838  }
839  }
840  }
841 
842  MEM_freeN(groups_array);
843  MEM_freeN(group_index);
844  }
845 
846  /* for PET we need islands of 1 so connected vertices can use it with V3D_AROUND_LOCAL_ORIGINS */
847  if (calc_single_islands) {
848  BMIter viter;
849  BMVert *v;
850  int group_tot_single = 0;
851 
852  BM_ITER_MESH_INDEX (v, &viter, bm, BM_VERTS_OF_MESH, i) {
853  if (BM_elem_flag_test(v, BM_ELEM_SELECT) && (data.island_vert_map[i] == -1)) {
854  group_tot_single += 1;
855  }
856  }
857 
858  if (group_tot_single != 0) {
859  if (calc_island_center) {
860  data.center = MEM_reallocN(data.center,
861  sizeof(*data.center) * (data.island_tot + group_tot_single));
862  }
863  if (calc_island_axismtx) {
864  data.axismtx = MEM_reallocN(data.axismtx,
865  sizeof(*data.axismtx) * (data.island_tot + group_tot_single));
866  }
867 
868  BM_ITER_MESH_INDEX (v, &viter, bm, BM_VERTS_OF_MESH, i) {
869  if (BM_elem_flag_test(v, BM_ELEM_SELECT) && (data.island_vert_map[i] == -1)) {
870  data.island_vert_map[i] = data.island_tot;
871  if (data.center) {
872  copy_v3_v3(data.center[data.island_tot], v->co);
873  }
874  if (data.axismtx) {
875  if (is_zero_v3(v->no) == false) {
876  axis_dominant_v3_to_m3(data.axismtx[data.island_tot], v->no);
877  invert_m3(data.axismtx[data.island_tot]);
878  }
879  else {
880  unit_m3(data.axismtx[data.island_tot]);
881  }
882  }
883 
884  data.island_tot += 1;
885  }
886  }
887  }
888  }
889 
890  *r_island_data = data;
891 }
892 
894 {
895  if (island_data->center) {
896  MEM_freeN(island_data->center);
897  }
898  if (island_data->axismtx) {
899  MEM_freeN(island_data->axismtx);
900  }
901  if (island_data->island_vert_map) {
902  MEM_freeN(island_data->island_vert_map);
903  }
904 }
905 
908 /* -------------------------------------------------------------------- */
912 /* Propagate distance from v1 and v2 to v0. */
913 static bool bmesh_test_dist_add(BMVert *v0,
914  BMVert *v1,
915  BMVert *v2,
916  float *dists,
917  /* optionally track original index */
918  int *index,
919  const float mtx[3][3])
920 {
921  if ((BM_elem_flag_test(v0, BM_ELEM_SELECT) == 0) &&
922  (BM_elem_flag_test(v0, BM_ELEM_HIDDEN) == 0)) {
923  const int i0 = BM_elem_index_get(v0);
924  const int i1 = BM_elem_index_get(v1);
925 
926  BLI_assert(dists[i1] != FLT_MAX);
927  if (dists[i0] <= dists[i1]) {
928  return false;
929  }
930 
931  float dist0;
932 
933  if (v2) {
934  /* Distance across triangle. */
935  const int i2 = BM_elem_index_get(v2);
936  BLI_assert(dists[i2] != FLT_MAX);
937  if (dists[i0] <= dists[i2]) {
938  return false;
939  }
940 
941  float vm0[3], vm1[3], vm2[3];
942  mul_v3_m3v3(vm0, mtx, v0->co);
943  mul_v3_m3v3(vm1, mtx, v1->co);
944  mul_v3_m3v3(vm2, mtx, v2->co);
945 
946  dist0 = geodesic_distance_propagate_across_triangle(vm0, vm1, vm2, dists[i1], dists[i2]);
947  }
948  else {
949  /* Distance along edge. */
950  float vec[3];
951  sub_v3_v3v3(vec, v1->co, v0->co);
952  mul_m3_v3(mtx, vec);
953 
954  dist0 = dists[i1] + len_v3(vec);
955  }
956 
957  if (dist0 < dists[i0]) {
958  dists[i0] = dist0;
959  if (index != NULL) {
960  index[i0] = index[i1];
961  }
962  return true;
963  }
964  }
965 
966  return false;
967 }
968 
969 static bool bmesh_test_loose_edge(BMEdge *edge)
970 {
971  /* Actual loose edge. */
972  if (edge->l == NULL) {
973  return true;
974  }
975 
976  /* Loose edge due to hidden adjacent faces. */
977  BMIter iter;
978  BMFace *face;
979  BM_ITER_ELEM (face, &iter, edge, BM_FACES_OF_EDGE) {
980  if (BM_elem_flag_test(face, BM_ELEM_HIDDEN) == 0) {
981  return false;
982  }
983  }
984  return true;
985 }
986 
988  const float mtx[3][3],
989  float *dists,
990  int *index)
991 {
993 
994  /* any BM_ELEM_TAG'd edge is in 'queue_next', so we don't add in twice */
995  const int tag_queued = BM_ELEM_TAG;
996  const int tag_loose = BM_ELEM_TAG_ALT;
997 
998  BLI_LINKSTACK_DECLARE(queue_next, BMEdge *);
999 
1001  BLI_LINKSTACK_INIT(queue_next);
1002 
1003  {
1004  /* Set indexes and initial distances for selected vertices. */
1005  BMIter viter;
1006  BMVert *v;
1007  int i;
1008 
1009  BM_ITER_MESH_INDEX (v, &viter, bm, BM_VERTS_OF_MESH, i) {
1010  float dist;
1011  BM_elem_index_set(v, i); /* set_inline */
1012 
1014  dist = FLT_MAX;
1015  if (index != NULL) {
1016  index[i] = i;
1017  }
1018  }
1019  else {
1020  dist = 0.0f;
1021  if (index != NULL) {
1022  index[i] = i;
1023  }
1024  }
1025 
1026  dists[i] = dist;
1027  }
1029  }
1030 
1031  {
1032  /* Add edges with at least one selected vertex to the queue. */
1033  BMIter eiter;
1034  BMEdge *e;
1035 
1036  BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
1037 
1038  /* Always clear to satisfy the assert, also predictable to leave in cleared state. */
1039  BM_elem_flag_disable(e, tag_queued);
1040 
1042  continue;
1043  }
1044 
1045  BMVert *v1 = e->v1;
1046  BMVert *v2 = e->v2;
1047  int i1 = BM_elem_index_get(v1);
1048  int i2 = BM_elem_index_get(v2);
1049 
1050  if (dists[i1] != FLT_MAX || dists[i2] != FLT_MAX) {
1052  }
1053  BM_elem_flag_set(e, tag_loose, bmesh_test_loose_edge(e));
1054  }
1055  }
1056 
1057  do {
1058  BMEdge *e;
1059 
1060  while ((e = BLI_LINKSTACK_POP(queue))) {
1061  BMVert *v1 = e->v1;
1062  BMVert *v2 = e->v2;
1063  int i1 = BM_elem_index_get(v1);
1064  int i2 = BM_elem_index_get(v2);
1065 
1066  if (BM_elem_flag_test(e, tag_loose) || (dists[i1] == FLT_MAX || dists[i2] == FLT_MAX)) {
1067  /* Propagate along edge from vertex with smallest to largest distance. */
1068  if (dists[i1] > dists[i2]) {
1069  SWAP(int, i1, i2);
1070  SWAP(BMVert *, v1, v2);
1071  }
1072 
1073  if (bmesh_test_dist_add(v2, v1, NULL, dists, index, mtx)) {
1074  /* Add adjacent loose edges to the queue, or all edges if this is a loose edge.
1075  * Other edges are handled by propagation across edges below. */
1076  BMEdge *e_other;
1077  BMIter eiter;
1078  BM_ITER_ELEM (e_other, &eiter, v2, BM_EDGES_OF_VERT) {
1079  if (e_other != e && BM_elem_flag_test(e_other, tag_queued) == 0 &&
1080  !BM_elem_flag_test(e_other, BM_ELEM_HIDDEN) &&
1081  (BM_elem_flag_test(e, tag_loose) || BM_elem_flag_test(e_other, tag_loose))) {
1082  BM_elem_flag_enable(e_other, tag_queued);
1083  BLI_LINKSTACK_PUSH(queue_next, e_other);
1084  }
1085  }
1086  }
1087  }
1088 
1089  if (!BM_elem_flag_test(e, tag_loose)) {
1090  /* Propagate across edge to vertices in adjacent faces. */
1091  BMLoop *l;
1092  BMIter liter;
1093  BM_ITER_ELEM (l, &liter, e, BM_LOOPS_OF_EDGE) {
1095  continue;
1096  }
1097  /* Don't check hidden edges or vertices in this loop
1098  * since any hidden edge causes the face to be hidden too. */
1099  for (BMLoop *l_other = l->next->next; l_other != l; l_other = l_other->next) {
1100  BMVert *v_other = l_other->v;
1101  BLI_assert(!ELEM(v_other, v1, v2));
1102 
1103  if (bmesh_test_dist_add(v_other, v1, v2, dists, index, mtx)) {
1104  /* Add adjacent edges to the queue, if they are ready to propagate across/along.
1105  * Always propagate along loose edges, and for other edges only propagate across
1106  * if both vertices have a known distances. */
1107  BMEdge *e_other;
1108  BMIter eiter;
1109  BM_ITER_ELEM (e_other, &eiter, v_other, BM_EDGES_OF_VERT) {
1110  if (e_other != e && BM_elem_flag_test(e_other, tag_queued) == 0 &&
1111  !BM_elem_flag_test(e_other, BM_ELEM_HIDDEN) &&
1112  (BM_elem_flag_test(e_other, tag_loose) ||
1113  dists[BM_elem_index_get(BM_edge_other_vert(e_other, v_other))] != FLT_MAX)) {
1114  BM_elem_flag_enable(e_other, tag_queued);
1115  BLI_LINKSTACK_PUSH(queue_next, e_other);
1116  }
1117  }
1118  }
1119  }
1120  }
1121  }
1122  }
1123 
1124  /* Clear for the next loop. */
1125  for (LinkNode *lnk = queue_next; lnk; lnk = lnk->next) {
1126  BMEdge *e_link = lnk->link;
1127 
1128  BM_elem_flag_disable(e_link, tag_queued);
1129  }
1130 
1131  BLI_LINKSTACK_SWAP(queue, queue_next);
1132 
1133  /* None should be tagged now since 'queue_next' is empty. */
1134  BLI_assert(BM_iter_mesh_count_flag(BM_EDGES_OF_MESH, bm, tag_queued, true) == 0);
1135  } while (BLI_LINKSTACK_SIZE(queue));
1136 
1138  BLI_LINKSTACK_FREE(queue_next);
1139 }
1140 
1143 /* -------------------------------------------------------------------- */
1147 /* Used for both mirror epsilon and TD_MIRROR_EDGE_ */
1148 #define TRANSFORM_MAXDIST_MIRROR 0.00002f
1149 
1150 static bool is_in_quadrant_v3(const float co[3], const int quadrant[3], const float epsilon)
1151 {
1152  if (quadrant[0] && ((co[0] * quadrant[0]) < -epsilon)) {
1153  return false;
1154  }
1155  if (quadrant[1] && ((co[1] * quadrant[1]) < -epsilon)) {
1156  return false;
1157  }
1158  if (quadrant[2] && ((co[2] * quadrant[2]) < -epsilon)) {
1159  return false;
1160  }
1161  return true;
1162 }
1163 
1165  const bool use_select,
1166  const bool use_topology,
1167  const bool mirror_axis[3],
1168  struct TransMirrorData *r_mirror_data)
1169 {
1170  struct MirrorDataVert *vert_map;
1171 
1172  BMesh *bm = em->bm;
1173  BMVert *eve;
1174  BMIter iter;
1175  int i, flag, totvert = bm->totvert;
1176 
1177  vert_map = MEM_callocN(totvert * sizeof(*vert_map), __func__);
1178 
1179  float select_sum[3] = {0};
1180  BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
1181  vert_map[i] = (struct MirrorDataVert){-1, 0};
1182  if (BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
1183  continue;
1184  }
1185  if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
1186  add_v3_v3(select_sum, eve->co);
1187  }
1188  }
1189 
1190  /* Tag only elements that will be transformed within the quadrant. */
1191  int quadrant[3];
1192  for (int a = 0; a < 3; a++) {
1193  if (mirror_axis[a]) {
1194  quadrant[a] = select_sum[a] >= 0.0f ? 1 : -1;
1195  }
1196  else {
1197  quadrant[a] = 0;
1198  }
1199  }
1200 
1201  uint mirror_elem_len = 0;
1202  int *index[3] = {NULL, NULL, NULL};
1203  bool is_single_mirror_axis = (mirror_axis[0] + mirror_axis[1] + mirror_axis[2]) == 1;
1204  bool test_selected_only = use_select && is_single_mirror_axis;
1205  for (int a = 0; a < 3; a++) {
1206  if (!mirror_axis[a]) {
1207  continue;
1208  }
1209 
1210  index[a] = MEM_mallocN(totvert * sizeof(*index[a]), __func__);
1212  em, a, false, test_selected_only, true, use_topology, TRANSFORM_MAXDIST_MIRROR, index[a]);
1213 
1214  flag = TD_MIRROR_X << a;
1215  BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) {
1216  int i_mirr = index[a][i];
1217  if (i_mirr < 0) {
1218  continue;
1219  }
1220  if (BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
1221  continue;
1222  }
1223  if (use_select && !BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
1224  continue;
1225  }
1226  if (!is_in_quadrant_v3(eve->co, quadrant, TRANSFORM_MAXDIST_MIRROR)) {
1227  continue;
1228  }
1229  if (vert_map[i_mirr].flag != 0) {
1230  /* One mirror per element.
1231  * It can happen when vertices occupy the same position. */
1232  continue;
1233  }
1234 
1235  vert_map[i_mirr] = (struct MirrorDataVert){i, flag};
1236  mirror_elem_len++;
1237  }
1238  }
1239 
1240  if (!mirror_elem_len) {
1241  MEM_freeN(vert_map);
1242  vert_map = NULL;
1243  }
1244  else if (!is_single_mirror_axis) {
1245  /* Adjustment for elements that are mirrors of mirrored elements. */
1246  for (int a = 0; a < 3; a++) {
1247  if (!mirror_axis[a]) {
1248  continue;
1249  }
1250 
1251  flag = TD_MIRROR_X << a;
1252  for (i = 0; i < totvert; i++) {
1253  int i_mirr = index[a][i];
1254  if (i_mirr < 0) {
1255  continue;
1256  }
1257  if (vert_map[i].index != -1 && !(vert_map[i].flag & flag)) {
1258  if (vert_map[i_mirr].index == -1) {
1259  mirror_elem_len++;
1260  }
1261  vert_map[i_mirr].index = vert_map[i].index;
1262  vert_map[i_mirr].flag |= vert_map[i].flag | flag;
1263  }
1264  }
1265  }
1266  }
1267 
1268  MEM_SAFE_FREE(index[0]);
1269  MEM_SAFE_FREE(index[1]);
1270  MEM_SAFE_FREE(index[2]);
1271 
1272  r_mirror_data->vert_map = vert_map;
1273  r_mirror_data->mirror_elem_len = mirror_elem_len;
1274 }
1275 
1277 {
1278  if (mirror_data->vert_map) {
1279  MEM_freeN(mirror_data->vert_map);
1280  }
1281 }
1282 
1285 /* -------------------------------------------------------------------- */
1290  struct TransDataContainer *tc,
1291  struct BMEditMesh *em,
1292  struct TransMeshDataCrazySpace *r_crazyspace_data)
1293 {
1294  float(*quats)[4] = NULL;
1295  float(*defmats)[3][3] = NULL;
1296  const int prop_mode = (t->flag & T_PROP_EDIT) ? (t->flag & T_PROP_EDIT_ALL) : 0;
1297  if (BKE_modifiers_get_cage_index(t->scene, tc->obedit, NULL, 1) != -1) {
1298  float(*defcos)[3] = NULL;
1299  int totleft = -1;
1300  if (BKE_modifiers_is_correctable_deformed(t->scene, tc->obedit)) {
1301  BKE_scene_graph_evaluated_ensure(t->depsgraph, CTX_data_main(t->context));
1302 
1303  /* Use evaluated state because we need b-bone cache. */
1304  Scene *scene_eval = (Scene *)DEG_get_evaluated_id(t->depsgraph, &t->scene->id);
1305  Object *obedit_eval = (Object *)DEG_get_evaluated_id(t->depsgraph, &tc->obedit->id);
1306  BMEditMesh *em_eval = BKE_editmesh_from_object(obedit_eval);
1307  /* check if we can use deform matrices for modifier from the
1308  * start up to stack, they are more accurate than quats */
1310  t->depsgraph, scene_eval, obedit_eval, em_eval, &defmats, &defcos);
1311  }
1312 
1313  /* If we still have more modifiers, also do crazy-space
1314  * correction with \a quats, relative to the coordinates after
1315  * the modifiers that support deform matrices \a defcos. */
1316 
1317 #if 0 /* TODO(campbell): fix crazy-space & extrude so it can be enabled for general use. */
1318  if ((totleft > 0) || (totleft == -1))
1319 #else
1320  if (totleft > 0)
1321 #endif
1322  {
1323  float(*mappedcos)[3] = NULL;
1324  mappedcos = BKE_crazyspace_get_mapped_editverts(t->depsgraph, tc->obedit);
1325  quats = MEM_mallocN(em->bm->totvert * sizeof(*quats), "crazy quats");
1326  BKE_crazyspace_set_quats_editmesh(em, defcos, mappedcos, quats, !prop_mode);
1327  if (mappedcos) {
1328  MEM_freeN(mappedcos);
1329  }
1330  }
1331 
1332  if (defcos) {
1333  MEM_freeN(defcos);
1334  }
1335  }
1336  r_crazyspace_data->quats = quats;
1337  r_crazyspace_data->defmats = defmats;
1338 }
1339 
1341  const float smtx[3][3],
1342  const float defmat[3][3],
1343  const float quat[4],
1344  struct TransData *r_td)
1345 {
1346  /* CrazySpace */
1347  if (quat || defmat) {
1348  float mat[3][3], qmat[3][3], imat[3][3];
1349 
1350  /* Use both or either quat and defmat correction. */
1351  if (quat) {
1352  quat_to_mat3(qmat, quat);
1353 
1354  if (defmat) {
1355  mul_m3_series(mat, defmat, qmat, mtx);
1356  }
1357  else {
1358  mul_m3_m3m3(mat, mtx, qmat);
1359  }
1360  }
1361  else {
1362  mul_m3_m3m3(mat, mtx, defmat);
1363  }
1364 
1365  invert_m3_m3(imat, mat);
1366 
1367  copy_m3_m3(r_td->smtx, imat);
1368  copy_m3_m3(r_td->mtx, mat);
1369  }
1370  else {
1371  copy_m3_m3(r_td->smtx, smtx);
1372  copy_m3_m3(r_td->mtx, mtx);
1373  }
1374 }
1375 
1377 {
1378  if (r_crazyspace_data->quats) {
1379  MEM_freeN(r_crazyspace_data->quats);
1380  }
1381  if (r_crazyspace_data->defmats) {
1382  MEM_freeN(r_crazyspace_data->defmats);
1383  }
1384 }
1385 
1388 /* -------------------------------------------------------------------- */
1392 static void tc_mesh_transdata_center_copy(const struct TransIslandData *island_data,
1393  const int island_index,
1394  const float iloc[3],
1395  float r_center[3])
1396 {
1397  if (island_data->center && island_index != -1) {
1398  copy_v3_v3(r_center, island_data->center[island_index]);
1399  }
1400  else {
1401  copy_v3_v3(r_center, iloc);
1402  }
1403 }
1404 
1405 /* way to overwrite what data is edited with transform */
1407  TransData *td,
1408  TransDataExtension *tx,
1409  BMEditMesh *em,
1410  BMVert *eve,
1411  const struct TransIslandData *island_data,
1412  const int island_index)
1413 {
1414  float *no, _no[3];
1416 
1417  td->flag = 0;
1418  // if (key)
1419  // td->loc = key->co;
1420  // else
1421  td->loc = eve->co;
1422  copy_v3_v3(td->iloc, td->loc);
1423 
1424  if ((t->mode == TFM_SHRINKFATTEN) && (em->selectmode & SCE_SELECT_FACE) &&
1426  (BM_vert_calc_normal_ex(eve, BM_ELEM_SELECT, _no))) {
1427  no = _no;
1428  }
1429  else {
1430  no = eve->no;
1431  }
1432 
1433  tc_mesh_transdata_center_copy(island_data, island_index, td->iloc, td->center);
1434 
1435  if ((island_index != -1) && island_data->axismtx) {
1436  copy_m3_m3(td->axismtx, island_data->axismtx[island_index]);
1437  }
1438  else if (t->around == V3D_AROUND_LOCAL_ORIGINS) {
1439  createSpaceNormal(td->axismtx, no);
1440  }
1441  else {
1442  /* Setting normals */
1443  copy_v3_v3(td->axismtx[2], no);
1444  td->axismtx[0][0] = td->axismtx[0][1] = td->axismtx[0][2] = td->axismtx[1][0] =
1445  td->axismtx[1][1] = td->axismtx[1][2] = 0.0f;
1446  }
1447 
1448  td->ext = NULL;
1449  td->val = NULL;
1450  td->extra = eve;
1451  if (t->mode == TFM_SHRINKFATTEN) {
1452  td->ext = tx;
1454  }
1455 }
1456 
1458 {
1460  TransDataExtension *tx = NULL;
1461  BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
1462  Mesh *me = tc->obedit->data;
1463  BMesh *bm = em->bm;
1464  BMVert *eve;
1465  BMIter iter;
1466  float mtx[3][3], smtx[3][3];
1467  int a;
1468  const int prop_mode = (t->flag & T_PROP_EDIT) ? (t->flag & T_PROP_EDIT_ALL) : 0;
1469 
1470  struct TransIslandData island_data = {NULL};
1471  struct TransMirrorData mirror_data = {NULL};
1472  struct TransMeshDataCrazySpace crazyspace_data = {NULL};
1473 
1481  /* Support other objects using PET to adjust these, unless connected is enabled. */
1482  if ((!prop_mode || (prop_mode & T_PROP_CONNECTED)) && (bm->totvertsel == 0)) {
1483  continue;
1484  }
1485 
1486  int data_len = 0;
1487  if (prop_mode) {
1488  BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
1489  if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
1490  data_len++;
1491  }
1492  }
1493  }
1494  else {
1495  data_len = bm->totvertsel;
1496  }
1497 
1498  if (data_len == 0) {
1499  continue;
1500  }
1501 
1502  /* Snap rotation along normal needs a common axis for whole islands,
1503  * otherwise one get random crazy results, see T59104.
1504  * However, we do not want to use the island center for the pivot/translation reference. */
1505  const bool is_snap_rotate = ((t->mode == TFM_TRANSLATION) &&
1506  /* There is not guarantee that snapping
1507  * is initialized yet at this point... */
1508  (usingSnappingNormal(t) ||
1509  (t->settings->snap_flag & SCE_SNAP_ROTATE) != 0) &&
1510  (t->around != V3D_AROUND_LOCAL_ORIGINS));
1511 
1512  /* Even for translation this is needed because of island-orientation, see: T51651. */
1513  const bool is_island_center = (t->around == V3D_AROUND_LOCAL_ORIGINS) || is_snap_rotate;
1514  if (is_island_center) {
1515  /* In this specific case, near-by vertices will need to know
1516  * the island of the nearest connected vertex. */
1517  const bool calc_single_islands = ((prop_mode & T_PROP_CONNECTED) &&
1518  (t->around == V3D_AROUND_LOCAL_ORIGINS) &&
1519  (em->selectmode & SCE_SELECT_VERTEX));
1520 
1521  const bool calc_island_center = !is_snap_rotate;
1522  /* The island axismtx is only necessary in some modes.
1523  * TODO(Germano): Extend the list to exclude other modes. */
1524  const bool calc_island_axismtx = !ELEM(t->mode, TFM_SHRINKFATTEN);
1525 
1527  em, calc_single_islands, calc_island_center, calc_island_axismtx, &island_data);
1528  }
1529 
1530  copy_m3_m4(mtx, tc->obedit->obmat);
1531  /* we use a pseudo-inverse so that when one of the axes is scaled to 0,
1532  * matrix inversion still works and we can still moving along the other */
1534 
1535  /* Original index of our connected vertex when connected distances are calculated.
1536  * Optional, allocate if needed. */
1537  int *dists_index = NULL;
1538  float *dists = NULL;
1539  if (prop_mode & T_PROP_CONNECTED) {
1540  dists = MEM_mallocN(bm->totvert * sizeof(float), __func__);
1541  if (is_island_center) {
1542  dists_index = MEM_mallocN(bm->totvert * sizeof(int), __func__);
1543  }
1544  transform_convert_mesh_connectivity_distance(em->bm, mtx, dists, dists_index);
1545  }
1546 
1547  /* Create TransDataMirror. */
1548  if (tc->use_mirror_axis_any) {
1549  bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0;
1550  bool use_select = (t->flag & T_PROP_EDIT) == 0;
1551  const bool mirror_axis[3] = {
1552  tc->use_mirror_axis_x, tc->use_mirror_axis_y, tc->use_mirror_axis_z};
1554  em, use_select, use_topology, mirror_axis, &mirror_data);
1555 
1556  if (mirror_data.vert_map) {
1557  tc->data_mirror_len = mirror_data.mirror_elem_len;
1558  tc->data_mirror = MEM_mallocN(mirror_data.mirror_elem_len * sizeof(*tc->data_mirror),
1559  __func__);
1560 
1561  BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, a) {
1562  if (prop_mode || BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
1563  if (mirror_data.vert_map[a].index != -1) {
1564  data_len--;
1565  }
1566  }
1567  }
1568  }
1569  }
1570 
1571  /* Detect CrazySpace [tm]. */
1572  transform_convert_mesh_crazyspace_detect(t, tc, em, &crazyspace_data);
1573 
1574  /* Create TransData. */
1575  BLI_assert(data_len >= 1);
1576  tc->data_len = data_len;
1577  tc->data = MEM_callocN(data_len * sizeof(TransData), "TransObData(Mesh EditMode)");
1578  if (t->mode == TFM_SHRINKFATTEN) {
1579  /* warning, this is overkill, we only need 2 extra floats,
1580  * but this stores loads of extra stuff, for TFM_SHRINKFATTEN its even more overkill
1581  * since we may not use the 'alt' transform mode to maintain shell thickness,
1582  * but with generic transform code its hard to lazy init vars */
1583  tx = tc->data_ext = MEM_callocN(tc->data_len * sizeof(TransDataExtension),
1584  "TransObData ext");
1585  }
1586 
1587  TransData *tob = tc->data;
1588  TransDataMirror *td_mirror = tc->data_mirror;
1589  BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, a) {
1590  if (BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) {
1591  continue;
1592  }
1593 
1594  int island_index = -1;
1595  if (island_data.island_vert_map) {
1596  const int connected_index = (dists_index && dists_index[a] != -1) ? dists_index[a] : a;
1597  island_index = island_data.island_vert_map[connected_index];
1598  }
1599 
1600  if (mirror_data.vert_map && mirror_data.vert_map[a].index != -1) {
1601  int elem_index = mirror_data.vert_map[a].index;
1602  BMVert *v_src = BM_vert_at_index(bm, elem_index);
1603 
1604  if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
1605  mirror_data.vert_map[a].flag |= TD_SELECTED;
1606  }
1607 
1608  td_mirror->extra = eve;
1609  td_mirror->loc = eve->co;
1610  copy_v3_v3(td_mirror->iloc, eve->co);
1611  td_mirror->flag = mirror_data.vert_map[a].flag;
1612  td_mirror->loc_src = v_src->co;
1614  &island_data, island_index, td_mirror->iloc, td_mirror->center);
1615 
1616  td_mirror++;
1617  }
1618  else if (prop_mode || BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
1619  /* Do not use the island center in case we are using islands
1620  * only to get axis for snap/rotate to normal... */
1621  VertsToTransData(t, tob, tx, em, eve, &island_data, island_index);
1622  if (tx) {
1623  tx++;
1624  }
1625 
1626  /* selected */
1627  if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) {
1628  tob->flag |= TD_SELECTED;
1629  }
1630 
1631  if (prop_mode) {
1632  if (prop_mode & T_PROP_CONNECTED) {
1633  tob->dist = dists[a];
1634  }
1635  else {
1636  tob->flag |= TD_NOTCONNECTED;
1637  tob->dist = FLT_MAX;
1638  }
1639  }
1640 
1641  /* CrazySpace */
1643  mtx,
1644  smtx,
1645  crazyspace_data.defmats ? crazyspace_data.defmats[a] : NULL,
1646  crazyspace_data.quats && BM_elem_flag_test(eve, BM_ELEM_TAG) ?
1647  crazyspace_data.quats[a] :
1648  NULL,
1649  tob);
1650 
1651  if (tc->use_mirror_axis_any) {
1652  if (tc->use_mirror_axis_x && fabsf(tob->loc[0]) < TRANSFORM_MAXDIST_MIRROR) {
1653  tob->flag |= TD_MIRROR_EDGE_X;
1654  }
1655  if (tc->use_mirror_axis_y && fabsf(tob->loc[1]) < TRANSFORM_MAXDIST_MIRROR) {
1656  tob->flag |= TD_MIRROR_EDGE_Y;
1657  }
1658  if (tc->use_mirror_axis_z && fabsf(tob->loc[2]) < TRANSFORM_MAXDIST_MIRROR) {
1659  tob->flag |= TD_MIRROR_EDGE_Z;
1660  }
1661  }
1662 
1663  tob++;
1664  }
1665  }
1666 
1669  transform_convert_mesh_crazyspace_free(&crazyspace_data);
1670  if (dists) {
1671  MEM_freeN(dists);
1672  }
1673  if (dists_index) {
1674  MEM_freeN(dists_index);
1675  }
1676  }
1677 }
1678 
1681 /* -------------------------------------------------------------------- */
1686  TransDataContainer *tc,
1687  enum ePartialType partial_type)
1688 {
1690 
1691  struct TransCustomData_PartialUpdate *pupdate = &tcmd->partial_update[partial_type];
1692 
1693  if (pupdate->cache) {
1694 
1695  /* Recalculate partial update data when the proportional editing size changes.
1696  *
1697  * Note that decreasing the proportional editing size requires the existing
1698  * partial data is used before recreating this partial data at the smaller size.
1699  * Since excluding geometry from being transformed requires an update.
1700  *
1701  * Extra logic is needed to account for this situation. */
1702 
1703  bool recalc;
1704  if (pupdate->prop_size_prev < t->prop_size) {
1705  /* Size increase, simply recalculate. */
1706  recalc = true;
1707  }
1708  else if (pupdate->prop_size_prev > t->prop_size) {
1709  /* Size decreased, first use this partial data since reducing the size will transform
1710  * geometry which needs recalculating. */
1711  pupdate->prop_size_prev = t->prop_size;
1712  recalc = false;
1713  }
1714  else if (pupdate->prop_size != t->prop_size) {
1715  BLI_assert(pupdate->prop_size > pupdate->prop_size_prev);
1716  recalc = true;
1717  }
1718  else {
1719  BLI_assert(t->prop_size == pupdate->prop_size_prev);
1720  recalc = false;
1721  }
1722 
1723  if (!recalc) {
1724  return pupdate->cache;
1725  }
1726 
1727  BM_mesh_partial_destroy(pupdate->cache);
1728  pupdate->cache = NULL;
1729  }
1730 
1732 
1734 
1735  /* Only use `verts_group` or `verts_mask`. */
1736  int *verts_group = NULL;
1737  int verts_group_count = 0; /* Number of non-zero elements in `verts_group`. */
1738 
1739  BLI_bitmap *verts_mask = NULL;
1740  int verts_mask_count = 0; /* Number of elements enabled in `verts_mask`. */
1741 
1742  if ((partial_type == PARTIAL_TYPE_GROUP) &&
1743  ((t->flag & T_PROP_EDIT) || tc->use_mirror_axis_any)) {
1744  verts_group = MEM_callocN(sizeof(*verts_group) * em->bm->totvert, __func__);
1745  int i;
1746  TransData *td;
1747  for (i = 0, td = tc->data; i < tc->data_len; i++, td++) {
1748  if (td->factor == 0.0f) {
1749  continue;
1750  }
1751  const BMVert *v = (BMVert *)td->extra;
1752  const int v_index = BM_elem_index_get(v);
1753  BLI_assert(verts_group[v_index] == 0);
1754  if (td->factor < 1.0f) {
1755  /* Don't use grouping logic with the factor is under 1.0. */
1756  verts_group[v_index] = -1;
1757  }
1758  else {
1759  BLI_assert(td->factor == 1.0f);
1760  verts_group[v_index] = 1;
1761  if (tc->use_mirror_axis_any) {
1762  /* Use bits 2-4 for central alignment (don't overlap the first bit). */
1763  const int flag = td->flag & (TD_MIRROR_EDGE_X | TD_MIRROR_EDGE_Y | TD_MIRROR_EDGE_Z);
1764  verts_group[v_index] |= (flag >> TD_MIRROR_EDGE_AXIS_SHIFT) << 1;
1765  }
1766  }
1767  verts_mask_count += 1;
1768  }
1769 
1770  TransDataMirror *td_mirror = tc->data_mirror;
1771  for (i = 0; i < tc->data_mirror_len; i++, td_mirror++) {
1772  BMVert *v_mirr = (BMVert *)POINTER_OFFSET(td_mirror->loc_src, -offsetof(BMVert, co));
1773  /* The equality check is to account for the case when topology mirror moves
1774  * the vertex from it's original location to match it's symmetrical position,
1775  * with proportional editing enabled. */
1776  const int v_mirr_index = BM_elem_index_get(v_mirr);
1777  if (verts_group[v_mirr_index] == 0 && equals_v3v3(td_mirror->loc, td_mirror->iloc)) {
1778  continue;
1779  }
1780 
1781  BMVert *v_mirr_other = (BMVert *)td_mirror->extra;
1782  /* This assert should never fail since there is no overlap
1783  * between mirrored vertices and non-mirrored. */
1784  BLI_assert(verts_group[BM_elem_index_get(v_mirr_other)] == 0);
1785  const int v_mirr_other_index = BM_elem_index_get(v_mirr_other);
1786 
1787  if (verts_group[v_mirr_index] == -1) {
1788  verts_group[v_mirr_other_index] = -1;
1789  }
1790  else {
1791  /* Use bits 5-8 for mirror (don't overlap previous bits). */
1792  const int flag = td_mirror->flag & (TD_MIRROR_X | TD_MIRROR_Y | TD_MIRROR_Z);
1793  verts_group[v_mirr_other_index] |= (flag >> TD_MIRROR_EDGE_AXIS_SHIFT) << 4;
1794  }
1795  verts_mask_count += 1;
1796  }
1797  }
1798  else {
1799  /* See the body of the comments in the previous block for details. */
1800  verts_mask = BLI_BITMAP_NEW(em->bm->totvert, __func__);
1801  int i;
1802  TransData *td;
1803  for (i = 0, td = tc->data; i < tc->data_len; i++, td++) {
1804  if (td->factor == 0.0f) {
1805  continue;
1806  }
1807  const BMVert *v = (BMVert *)td->extra;
1808  const int v_index = BM_elem_index_get(v);
1809  BLI_assert(!BLI_BITMAP_TEST(verts_mask, v_index));
1810  BLI_BITMAP_ENABLE(verts_mask, v_index);
1811  verts_mask_count += 1;
1812  }
1813 
1814  TransDataMirror *td_mirror = tc->data_mirror;
1815  for (i = 0; i < tc->data_mirror_len; i++, td_mirror++) {
1816  BMVert *v_mirr = (BMVert *)POINTER_OFFSET(td_mirror->loc_src, -offsetof(BMVert, co));
1817  if (!BLI_BITMAP_TEST(verts_mask, BM_elem_index_get(v_mirr)) &&
1818  equals_v3v3(td_mirror->loc, td_mirror->iloc)) {
1819  continue;
1820  }
1821 
1822  BMVert *v_mirr_other = (BMVert *)td_mirror->extra;
1823  BLI_assert(!BLI_BITMAP_TEST(verts_mask, BM_elem_index_get(v_mirr_other)));
1824  const int v_mirr_other_index = BM_elem_index_get(v_mirr_other);
1825  BLI_BITMAP_ENABLE(verts_mask, v_mirr_other_index);
1826  verts_mask_count += 1;
1827  }
1828  }
1829 
1830  switch (partial_type) {
1831  case PARTIAL_TYPE_ALL: {
1834  .do_tessellate = true,
1835  .do_normals = true,
1836  },
1837  verts_mask,
1838  verts_mask_count);
1839  break;
1840  }
1841  case PARTIAL_TYPE_GROUP: {
1842  pupdate->cache =
1845  .do_tessellate = true,
1846  .do_normals = true,
1847  },
1848  verts_group,
1849  verts_group_count) :
1852  .do_tessellate = true,
1853  .do_normals = true,
1854  },
1855  verts_mask,
1856  verts_mask_count));
1857  break;
1858  }
1859  case PARTIAL_NONE: {
1861  }
1862  }
1863 
1864  if (verts_group) {
1865  MEM_freeN(verts_group);
1866  }
1867  else {
1868  MEM_freeN(verts_mask);
1869  }
1870 
1871  pupdate->prop_size_prev = t->prop_size;
1872  pupdate->prop_size = t->prop_size;
1873 
1874  return pupdate->cache;
1875 }
1876 
1877 static void tc_mesh_partial_types_calc(TransInfo *t, struct PartialTypeState *r_partial_state)
1878 {
1879  /* Calculate the kind of partial updates which can be performed. */
1880  enum ePartialType partial_for_normals = PARTIAL_NONE;
1881  enum ePartialType partial_for_looptri = PARTIAL_NONE;
1882 
1883  /* Note that operations such as #TFM_CREASE are not handled here
1884  * (if they were, leaving as #PARTIAL_NONE would be appropriate). */
1885  switch (t->mode) {
1886  case TFM_TRANSLATION: {
1887  partial_for_looptri = PARTIAL_TYPE_GROUP;
1888  partial_for_normals = PARTIAL_TYPE_GROUP;
1889  /* Translation can rotate when snapping to normal. */
1891  partial_for_normals = PARTIAL_TYPE_ALL;
1892  }
1893  break;
1894  }
1895  case TFM_ROTATION: {
1896  partial_for_looptri = PARTIAL_TYPE_GROUP;
1897  partial_for_normals = PARTIAL_TYPE_ALL;
1898  break;
1899  }
1900  case TFM_RESIZE: {
1901  partial_for_looptri = PARTIAL_TYPE_GROUP;
1902  partial_for_normals = PARTIAL_TYPE_GROUP;
1903  /* Non-uniform scale needs to recalculate all normals
1904  * since their relative locations change.
1905  * Uniform negative scale can keep normals as-is since the faces are flipped,
1906  * normals remain unchanged. */
1907  if ((t->con.mode & CON_APPLY) ||
1908  (t->values_final[0] != t->values_final[1] || t->values_final[0] != t->values_final[2])) {
1909  partial_for_normals = PARTIAL_TYPE_ALL;
1910  }
1911  break;
1912  }
1913  default: {
1914  partial_for_looptri = PARTIAL_TYPE_ALL;
1915  partial_for_normals = PARTIAL_TYPE_ALL;
1916  break;
1917  }
1918  }
1919 
1920  /* With projection, transform isn't affine. */
1922  if (partial_for_looptri == PARTIAL_TYPE_GROUP) {
1923  partial_for_looptri = PARTIAL_TYPE_ALL;
1924  }
1925  if (partial_for_normals == PARTIAL_TYPE_GROUP) {
1926  partial_for_normals = PARTIAL_TYPE_ALL;
1927  }
1928  }
1929 
1930  r_partial_state->for_looptri = partial_for_looptri;
1931  r_partial_state->for_normals = partial_for_normals;
1932 }
1933 
1935  TransDataContainer *tc,
1936  const struct PartialTypeState *partial_state)
1937 {
1939 
1941 
1942  const struct PartialTypeState *partial_state_prev = &tcmd->partial_update_state_prev;
1943 
1944  /* Promote the partial update types based on the previous state
1945  * so the values that no longer modified are reset before being left as-is.
1946  * Needed for translation which can toggle snap-to-normal during transform. */
1947  const enum ePartialType partial_for_looptri = MAX2(partial_state->for_looptri,
1948  partial_state_prev->for_looptri);
1949  const enum ePartialType partial_for_normals = MAX2(partial_state->for_normals,
1950  partial_state_prev->for_normals);
1951 
1952  if ((partial_for_looptri == PARTIAL_TYPE_ALL) && (partial_for_normals == PARTIAL_TYPE_ALL) &&
1953  (em->bm->totvert == em->bm->totvertsel)) {
1954  /* The additional cost of generating the partial connectivity data isn't justified
1955  * when all data needs to be updated.
1956  *
1957  * While proportional editing can cause all geometry to need updating with a partial
1958  * selection. It's impractical to calculate this ahead of time. Further, the down side of
1959  * using partial updates when their not needed is negligible. */
1961  }
1962  else {
1963  if (partial_for_looptri != PARTIAL_NONE) {
1964  BMPartialUpdate *bmpinfo = tc_mesh_partial_ensure(t, tc, partial_for_looptri);
1966  bmpinfo,
1967  &(const struct BMeshCalcTessellation_Params){
1968  .face_normals = true,
1969  });
1970  }
1971 
1972  if (partial_for_normals != PARTIAL_NONE) {
1973  BMPartialUpdate *bmpinfo = tc_mesh_partial_ensure(t, tc, partial_for_normals);
1974  /* While not a large difference, take advantage of existing normals where possible. */
1975  const bool face_normals = !((partial_for_looptri == PARTIAL_TYPE_ALL) ||
1976  ((partial_for_looptri == PARTIAL_TYPE_GROUP) &&
1977  (partial_for_normals == PARTIAL_TYPE_GROUP)));
1979  bmpinfo,
1980  &(const struct BMeshNormalsUpdate_Params){
1981  .face_normals = face_normals,
1982  });
1983  }
1984  }
1985 
1986  /* Store the previous requested (not the previous used),
1987  * since the values used may have been promoted based on the previous types. */
1988  tcmd->partial_update_state_prev = *partial_state;
1989 }
1990 
1993 /* -------------------------------------------------------------------- */
1998 {
1999  if (tc->use_mirror_axis_any) {
2000  int i;
2001  TransData *td;
2002  for (i = 0, td = tc->data; i < tc->data_len; i++, td++) {
2003  if (td->flag & (TD_MIRROR_EDGE_X | TD_MIRROR_EDGE_Y | TD_MIRROR_EDGE_Z)) {
2004  if (td->flag & TD_MIRROR_EDGE_X) {
2005  td->loc[0] = 0.0f;
2006  }
2007  if (td->flag & TD_MIRROR_EDGE_Y) {
2008  td->loc[1] = 0.0f;
2009  }
2010  if (td->flag & TD_MIRROR_EDGE_Z) {
2011  td->loc[2] = 0.0f;
2012  }
2013  }
2014  }
2015 
2016  TransDataMirror *td_mirror = tc->data_mirror;
2017  for (i = 0; i < tc->data_mirror_len; i++, td_mirror++) {
2018  copy_v3_v3(td_mirror->loc, td_mirror->loc_src);
2019  if (td_mirror->flag & TD_MIRROR_X) {
2020  td_mirror->loc[0] *= -1;
2021  }
2022  if (td_mirror->flag & TD_MIRROR_Y) {
2023  td_mirror->loc[1] *= -1;
2024  }
2025  if (td_mirror->flag & TD_MIRROR_Z) {
2026  td_mirror->loc[2] *= -1;
2027  }
2028  }
2029  }
2030 }
2031 
2033 {
2034  bool is_canceling = t->state == TRANS_CANCEL;
2035  /* Apply corrections. */
2036  if (!is_canceling) {
2038 
2039  bool do_mirror = !(t->flag & T_NO_MIRROR);
2041  /* Apply clipping after so we never project past the clip plane T25423. */
2043 
2044  if (do_mirror) {
2046  }
2047 
2049  }
2050  }
2051  else {
2053  }
2054 
2055  struct PartialTypeState partial_state;
2056  tc_mesh_partial_types_calc(t, &partial_state);
2057 
2059  DEG_id_tag_update(tc->obedit->data, ID_RECALC_GEOMETRY);
2060 
2061  tc_mesh_partial_update(t, tc, &partial_state);
2062  }
2063 }
2064 
2067 /* -------------------------------------------------------------------- */
2072 {
2073  const bool is_canceling = (t->state == TRANS_CANCEL);
2074  const bool use_automerge = !is_canceling && (t->flag & (T_AUTOMERGE | T_AUTOSPLIT)) != 0;
2075 
2076  if (!is_canceling && ELEM(t->mode, TFM_EDGE_SLIDE, TFM_VERT_SLIDE)) {
2077  /* NOTE(joeedh): Handle multi-res re-projection,
2078  * done on transform completion since it's really slow. */
2081  }
2082  }
2083 
2084  if (use_automerge) {
2086  BMEditMesh *em = BKE_editmesh_from_object(tc->obedit);
2087  BMesh *bm = em->bm;
2088  char hflag;
2089  bool has_face_sel = (bm->totfacesel != 0);
2090 
2091  if (tc->use_mirror_axis_any) {
2092  /* Rather than adjusting the selection (which the user would notice)
2093  * tag all mirrored verts, then auto-merge those. */
2095 
2096  TransDataMirror *td_mirror = tc->data_mirror;
2097  for (int i = tc->data_mirror_len; i--; td_mirror++) {
2098  BM_elem_flag_enable((BMVert *)td_mirror->extra, BM_ELEM_TAG);
2099  }
2100 
2101  hflag = BM_ELEM_SELECT | BM_ELEM_TAG;
2102  }
2103  else {
2104  hflag = BM_ELEM_SELECT;
2105  }
2106 
2107  if (t->flag & T_AUTOSPLIT) {
2109  tc->obedit, true, true, true, hflag, t->scene->toolsettings->doublimit);
2110  }
2111  else {
2112  EDBM_automerge(tc->obedit, true, hflag, t->scene->toolsettings->doublimit);
2113  }
2114 
2115  /* Special case, this is needed or faces won't re-select.
2116  * Flush selected edges to faces. */
2117  if (has_face_sel && (em->selectmode == SCE_SELECT_FACE)) {
2119  }
2120  }
2121  }
2122 
2124  /* table needs to be created for each edit command, since vertices can move etc */
2126  /* TODO(campbell): xform: We need support for many mirror objects at once! */
2127  break;
2128  }
2129 }
2130 
2134  /* flags */ (T_EDIT | T_POINTS),
2135  /* createTransData */ createTransEditVerts,
2136  /* recalcData */ recalcData_mesh,
2137  /* special_aftertrans_update */ special_aftertrans_update__mesh,
2138 };
typedef float(TangentPoint)[2]
struct Main * CTX_data_main(const bContext *C)
Definition: context.c:1074
int BKE_crazyspace_get_first_deform_matrices_editbmesh(struct Depsgraph *depsgraph, struct Scene *, struct Object *, struct BMEditMesh *em, float(**deformmats)[3][3], float(**deformcos)[3])
Definition: crazyspace.cc:233
void BKE_crazyspace_set_quats_editmesh(struct BMEditMesh *em, float(*origcos)[3], float(*mappedcos)[3], float(*quats)[4], bool use_select)
Definition: crazyspace.cc:118
float(* BKE_crazyspace_get_mapped_editverts(struct Depsgraph *depsgraph, struct Object *obedit))[3]
Definition: crazyspace.cc:89
bool CustomData_has_math(const struct CustomData *data)
bool CustomData_has_layer(const struct CustomData *data, int type)
bool CustomData_layer_has_math(const struct CustomData *data, int layer_n)
int CustomData_get_offset(const struct CustomData *data, int type)
void BKE_editmesh_looptri_and_normals_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:58
void BKE_editmesh_looptri_calc_with_partial_ex(BMEditMesh *em, struct BMPartialUpdate *bmpinfo, const struct BMeshCalcTessellation_Params *params)
Definition: editmesh.c:147
bool BKE_modifiers_is_correctable_deformed(const struct Scene *scene, struct Object *ob)
int BKE_modifiers_get_cage_index(const struct Scene *scene, struct Object *ob, int *r_lastPossibleCageIndex, bool is_virtual)
void BKE_scene_graph_evaluated_ensure(struct Depsgraph *depsgraph, struct Main *bmain)
Definition: scene.cc:2653
#define BLI_array_alloca(arr, realsize)
Definition: BLI_alloca.h:22
#define BLI_assert_unreachable()
Definition: BLI_assert.h:93
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define BLI_BITMAP_NEW(_num, _alloc_string)
Definition: BLI_bitmap.h:40
#define BLI_BITMAP_TEST(_bitmap, _index)
Definition: BLI_bitmap.h:64
#define BLI_BITMAP_ENABLE(_bitmap, _index)
Definition: BLI_bitmap.h:81
unsigned int BLI_bitmap
Definition: BLI_bitmap.h:16
BLI_INLINE void * BLI_ghashIterator_getKey(GHashIterator *ghi) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.h:298
BLI_INLINE void * BLI_ghashIterator_getValue(GHashIterator *ghi) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.h:302
#define GHASH_ITER(gh_iter_, ghash_)
Definition: BLI_ghash.h:321
void * BLI_ghash_lookup(const GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:734
GHash * BLI_ghash_ptr_new_ex(const char *info, unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
void BLI_ghash_insert(GHash *gh, void *key, void *val)
Definition: BLI_ghash.c:710
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition: BLI_ghash.c:863
GHash * BLI_ghash_ptr_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT
bool BLI_ghash_ensure_p(GHash *gh, void *key, void ***r_val) ATTR_WARN_UNUSED_RESULT
Definition: BLI_ghash.c:755
float geodesic_distance_propagate_across_triangle(const float v0[3], const float v1[3], const float v2[3], float dist1, float dist2)
Definition: math_geom.c:5922
void axis_dominant_v3_to_m3(float r_mat[3][3], const float normal[3])
Normal to x,y matrix.
Definition: math_geom.c:3527
float dist_signed_squared_to_corner_v3v3v3(const float p[3], const float v1[3], const float v2[3], const float v3[3], const float axis_ref[3])
Definition: math_geom.c:512
void mul_m3_v3(const float M[3][3], float r[3])
Definition: math_matrix.c:926
void copy_m3_m3(float m1[3][3], const float m2[3][3])
Definition: math_matrix.c:71
void unit_m3(float m[3][3])
Definition: math_matrix.c:40
void copy_m3_m4(float m1[3][3], const float m2[4][4])
Definition: math_matrix.c:87
#define PSEUDOINVERSE_EPSILON
bool invert_m3_m3(float R[3][3], const float A[3][3])
Definition: math_matrix.c:1180
bool invert_m3(float R[3][3])
Definition: math_matrix.c:1171
void mul_v3_m3v3(float r[3], const float M[3][3], const float a[3])
Definition: math_matrix.c:897
#define mul_m3_series(...)
void mul_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3])
Definition: math_matrix.c:388
void pseudoinverse_m3_m3(float Ainv[3][3], const float A[3][3], float epsilon)
Definition: math_matrix.c:3107
void quat_to_mat3(float mat[3][3], const float q[4])
MINLINE float normalize_v3(float r[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_v3_v3(float r[3], const float a[3])
MINLINE bool is_zero_v3(const float a[3]) ATTR_WARN_UNUSED_RESULT
void project_plane_normalized_v3_v3v3(float out[3], const float p[3], const float v_plane[3])
Definition: math_vector.c:652
void copy_vn_i(int *array_tar, int size, int val)
Definition: math_vector.c:1223
MINLINE bool equals_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
MINLINE void zero_v3(float r[3])
float angle_v3v3v3(const float a[3], const float b[3], const float c[3]) ATTR_WARN_UNUSED_RESULT
Definition: math_vector.c:361
MINLINE void mul_v3_v3fl(float r[3], const float a[3], float f)
MINLINE void add_v3_v3(float r[3], const float a[3])
MINLINE float len_v3(const float a[3]) ATTR_WARN_UNUSED_RESULT
void BLI_memarena_free(struct MemArena *ma) ATTR_NONNULL(1)
Definition: BLI_memarena.c:94
struct MemArena * BLI_memarena_new(size_t bufsize, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL ATTR_NONNULL(2) ATTR_MALLOC
Definition: BLI_memarena.c:64
#define BLI_MEMARENA_STD_BUFSIZE
Definition: BLI_memarena.h:20
void * BLI_memarena_alloc(struct MemArena *ma, size_t size) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC ATTR_ALLOC_SIZE(2)
Definition: BLI_memarena.c:116
unsigned int uint
Definition: BLI_sys_types.h:67
#define ARRAY_SIZE(arr)
#define SWAP(type, a, b)
#define UNUSED(x)
#define UNPACK3(a)
#define MAX2(a, b)
#define UNLIKELY(x)
#define ELEM(...)
#define POINTER_OFFSET(v, ofs)
void DEG_id_tag_update(struct ID *id, int flag)
struct ID * DEG_get_evaluated_id(const struct Depsgraph *depsgraph, struct ID *id)
@ ID_RECALC_GEOMETRY
Definition: DNA_ID.h:791
@ ME_EDIT_MIRROR_TOPO
#define SCE_SELECT_FACE
#define UVCALC_TRANSFORM_CORRECT_SLIDE
#define SCE_SELECT_VERTEX
#define UVCALC_TRANSFORM_CORRECT_KEEP_CONNECTED
@ SCE_SNAP_ROTATE
#define UVCALC_TRANSFORM_CORRECT
#define SCE_SELECT_EDGE
@ V3D_AROUND_LOCAL_ORIGINS
void EDBM_automerge_and_split(struct Object *ob, bool split_edges, bool split_faces, bool update, char hflag, float dist)
void EDBM_verts_mirror_cache_begin_ex(struct BMEditMesh *em, int axis, bool use_self, bool use_select, bool respecthide, bool use_topology, float maxdist, int *r_index)
void EDBM_automerge(struct Object *ob, bool update, char hflag, float dist)
void EDBM_selectmode_flush_ex(struct BMEditMesh *em, short selectmode)
void ED_mesh_mirror_spatial_table_end(struct Object *ob)
@ TFM_RESIZE
Definition: ED_transform.h:32
@ TFM_EDGE_SLIDE
Definition: ED_transform.h:59
@ TFM_SHEAR
Definition: ED_transform.h:35
@ TFM_SHRINKFATTEN
Definition: ED_transform.h:37
@ TFM_VERT_SLIDE
Definition: ED_transform.h:60
@ TFM_BEND
Definition: ED_transform.h:36
@ TFM_ROTATION
Definition: ED_transform.h:31
@ TFM_ALIGN
Definition: ED_transform.h:58
@ TFM_TOSPHERE
Definition: ED_transform.h:34
@ TFM_TRANSLATION
Definition: ED_transform.h:30
@ TFM_PUSHPULL
Definition: ED_transform.h:40
@ TFM_TRACKBALL
Definition: ED_transform.h:39
_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 const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint i1
_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 const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble u2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLdouble GLdouble v2 _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLdouble GLdouble nz _GL_VOID_RET _GL_VOID GLfloat GLfloat nz _GL_VOID_RET _GL_VOID GLint GLint nz _GL_VOID_RET _GL_VOID GLshort GLshort nz _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const GLfloat *values _GL_VOID_RET _GL_VOID GLsizei const GLushort *values _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID const GLuint const GLclampf *priorities _GL_VOID_RET _GL_VOID GLdouble y _GL_VOID_RET _GL_VOID GLfloat y _GL_VOID_RET _GL_VOID GLint y _GL_VOID_RET _GL_VOID GLshort y _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLfloat GLfloat z _GL_VOID_RET _GL_VOID GLint GLint z _GL_VOID_RET _GL_VOID GLshort GLshort z _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble w _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat w _GL_VOID_RET _GL_VOID GLint GLint GLint w _GL_VOID_RET _GL_VOID GLshort GLshort GLshort w _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble y2 _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat y2 _GL_VOID_RET _GL_VOID GLint GLint GLint y2 _GL_VOID_RET _GL_VOID GLshort GLshort GLshort y2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLuint *buffer _GL_VOID_RET _GL_VOID GLdouble t _GL_VOID_RET _GL_VOID GLfloat t _GL_VOID_RET _GL_VOID GLint t _GL_VOID_RET _GL_VOID GLshort t _GL_VOID_RET _GL_VOID GLdouble t
_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 const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble v1
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
#define MEM_reallocN(vmemh, len)
#define C
Definition: RandGen.cpp:25
#define BM_FACE_FIRST_LOOP(p)
Definition: bmesh_class.h:622
@ BM_LOOP
Definition: bmesh_class.h:385
@ 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
@ BM_ELEM_TAG_ALT
Definition: bmesh_class.h:489
void BM_elem_attrs_copy(BMesh *bm_src, BMesh *bm_dst, const void *ele_src, void *ele_dst)
void BM_mesh_copy_init_customdata_all_layers(BMesh *bm_dst, BMesh *bm_src, const char htype, const BMAllocTemplate *allocsize)
BMFace * BM_face_copy(BMesh *bm_dst, BMesh *bm_src, BMFace *f, const bool copy_verts, const bool copy_edges)
Definition: bmesh_core.c:279
#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_set(ele, hflag, val)
Definition: bmesh_inline.h:16
#define BM_elem_index_set(ele, index)
Definition: bmesh_inline.h:111
#define BM_elem_flag_test(ele, hflag)
Definition: bmesh_inline.h:12
#define BM_elem_flag_enable(ele, hflag)
Definition: bmesh_inline.h:14
LinkNode * BM_vert_loop_groups_data_layer_create(BMesh *bm, BMVert *v, const int layer_n, const float *loop_weights, MemArena *arena)
void BM_face_interp_multires_ex(BMesh *bm, BMFace *f_dst, const BMFace *f_src, const float f_dst_center[3], const float f_src_center[3], const int cd_loop_mdisp_offset)
Definition: bmesh_interp.c:544
void BM_vert_loop_groups_data_layer_merge(BMesh *bm, LinkNode *groups, const int layer_n)
void BM_vert_loop_groups_data_layer_merge_weights(BMesh *bm, LinkNode *groups, const int layer_n, const float *loop_weights)
void BM_loop_interp_from_face(BMesh *bm, BMLoop *l_dst, const BMFace *f_src, const bool do_vertex, const bool do_multires)
Definition: bmesh_interp.c:682
int BM_iter_mesh_count_flag(const char itype, BMesh *bm, const char hflag, const bool value)
Mesh Iter Flag Count.
#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_FACES_OF_EDGE
@ BM_EDGES_OF_MESH
@ BM_VERTS_OF_MESH
@ BM_VERTS_OF_EDGE
@ BM_VERTS_OF_FACE
@ BM_LOOPS_OF_VERT
@ BM_LOOPS_OF_EDGE
@ BM_EDGES_OF_VERT
@ BM_LOOPS_OF_FACE
#define BM_ITER_ELEM_INDEX(ele, iter, data, itype, indexvar)
BLI_INLINE bool BM_iter_init(BMIter *iter, BMesh *bm, const char itype, void *data)
Iterator Init.
ATTR_WARN_UNUSED_RESULT BMesh const char itype
ATTR_WARN_UNUSED_RESULT BMesh * bm
void BM_editselection_center(BMEditSelection *ese, float r_center[3])
void BM_editselection_plane(BMEditSelection *ese, float r_plane[3])
void BM_editselection_normal(BMEditSelection *ese, float r_normal[3])
void BM_mesh_elem_hflag_disable_all(BMesh *bm, const char htype, const char hflag, const bool respecthide)
const BMAllocTemplate bm_mesh_allocsize_default
Definition: bmesh_mesh.cc:23
void BM_mesh_free(BMesh *bm)
BMesh Free Mesh.
Definition: bmesh_mesh.cc:258
BMesh * BM_mesh_create(const BMAllocTemplate *allocsize, const struct BMeshCreateParams *params)
Definition: bmesh_mesh.cc:125
void bmesh_edit_begin(BMesh *UNUSED(bm), BMOpTypeFlag UNUSED(type_flag))
Definition: bmesh_mesh.cc:272
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
void bmesh_edit_end(BMesh *bm, BMOpTypeFlag type_flag)
BMesh End Edit.
Definition: bmesh_mesh.cc:292
BLI_INLINE BMVert * BM_vert_at_index(BMesh *bm, const int index)
Definition: bmesh_mesh.h:103
void BM_mesh_normals_update_with_partial_ex(BMesh *UNUSED(bm), const BMPartialUpdate *bmpinfo, const struct BMeshNormalsUpdate_Params *params)
void BM_mesh_partial_destroy(BMPartialUpdate *bmpinfo)
BMPartialUpdate * BM_mesh_partial_create_from_verts_group_single(BMesh *bm, const BMPartialUpdate_Params *params, const BLI_bitmap *verts_mask, const int verts_mask_count)
BMPartialUpdate * BM_mesh_partial_create_from_verts_group_multi(BMesh *bm, const BMPartialUpdate_Params *params, const int *verts_group, const int verts_group_count)
BMPartialUpdate * BM_mesh_partial_create_from_verts(BMesh *bm, const BMPartialUpdate_Params *params, const BLI_bitmap *verts_mask, const int verts_mask_count)
@ BMO_OPTYPE_FLAG_UNTAN_MULTIRES
bool BM_vert_calc_normal_ex(const BMVert *v, const char hflag, float r_no[3])
void BM_face_calc_center_median(const BMFace *f, float r_cent[3])
BMLoop * BM_loop_find_next_nodouble(BMLoop *l, BMLoop *l_stop, const float eps_sq)
Definition: bmesh_query.c:1163
int BM_mesh_calc_face_groups(BMesh *bm, int *r_groups_array, int(**r_group_index)[2], BMLoopFilterFunc filter_fn, BMLoopPairFilterFunc filter_pair_fn, void *user_data, const char hflag_test, const char htype_step)
Definition: bmesh_query.c:2094
float BM_vert_calc_shell_factor_ex(const BMVert *v, const float no[3], const char hflag)
Definition: bmesh_query.c:1438
BMLoop * BM_loop_find_prev_nodouble(BMLoop *l, BMLoop *l_stop, const float eps_sq)
Definition: bmesh_query.c:1146
int BM_mesh_calc_edge_groups(BMesh *bm, int *r_groups_array, int(**r_group_index)[2], BMVertFilterFunc filter_fn, void *user_data, const char hflag_test)
Definition: bmesh_query.c:2245
BLI_INLINE BMVert * BM_edge_other_vert(BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
ATTR_WARN_UNUSED_RESULT const BMVert * v2
ATTR_WARN_UNUSED_RESULT const BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMVert * v
SyclQueue * queue
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
#define fabsf(x)
Definition: metal/compat.h:219
bool isfinite(uchar)
Definition: scene/image.cpp:31
static unsigned a[3]
Definition: RandGen.cpp:78
static double epsilon
const btScalar eps
Definition: poly34.cpp:11
#define FOREACH_TRANS_DATA_CONTAINER(t, th)
short selectmode
Definition: BKE_editmesh.h:52
struct BMesh * bm
Definition: BKE_editmesh.h:40
int len
Definition: bmesh_class.h:267
float no[3]
Definition: bmesh_class.h:271
struct BMVert * v
Definition: bmesh_class.h:153
struct BMLoop * radial_next
Definition: bmesh_class.h:204
struct BMLoop * prev
Definition: bmesh_class.h:233
struct BMFace * f
Definition: bmesh_class.h:171
struct BMLoop * next
Definition: bmesh_class.h:233
float co[3]
Definition: bmesh_class.h:87
float no[3]
Definition: bmesh_class.h:88
int totvert
Definition: bmesh_class.h:297
BMEdge ** etable
Definition: bmesh_class.h:322
int totfacesel
Definition: bmesh_class.h:298
int shapenr
Definition: bmesh_class.h:353
char elem_index_dirty
Definition: bmesh_class.h:305
int totvertsel
Definition: bmesh_class.h:298
int totedgesel
Definition: bmesh_class.h:298
CustomData ldata
Definition: bmesh_class.h:337
BMFace ** ftable
Definition: bmesh_class.h:323
struct LinkNode * next
Definition: BLI_linklist.h:23
char editflag
enum ePartialType for_looptri
enum ePartialType for_normals
struct TransCustomDataMergeGroup * data
struct TransCustomDataLayer::@605 merge_group
struct TransCustomData_PartialUpdate partial_update[PARTIAL_TYPE_MAX]
struct TransCustomDataLayer * cd_layer_correct
struct PartialTypeState partial_update_state_prev
struct BMPartialUpdate * cache
void(* free_cb)(struct TransInfo *, struct TransDataContainer *tc, struct TransCustomData *custom_data)
float smtx[3][3]
float axismtx[3][3]
float mtx[3][3]
TransDataExtension * ext
float * val
float(* axismtx)[3][3]
struct MirrorDataVert * vert_map
void transform_convert_clip_mirror_modifier_apply(TransDataContainer *tc)
conversion and adaptation of different datablocks to a common struct.
void transform_convert_mesh_islanddata_free(struct TransIslandData *island_data)
void transform_convert_mesh_mirrordata_calc(struct BMEditMesh *em, const bool use_select, const bool use_topology, const bool mirror_axis[3], struct TransMirrorData *r_mirror_data)
#define FACE_SUBSTITUTE_INDEX
static void tc_mesh_customdatacorrect_create(TransDataContainer *tc, const bool use_merge_group)
static void tc_mesh_customdatacorrect_free(struct TransCustomDataLayer *tcld)
static void VertsToTransData(TransInfo *t, TransData *td, TransDataExtension *tx, BMEditMesh *em, BMVert *eve, const struct TransIslandData *island_data, const int island_index)
static void tc_mesh_transdata_center_copy(const struct TransIslandData *island_data, const int island_index, const float iloc[3], float r_center[3])
static void tc_mesh_customdata_free(struct TransCustomDataMesh *tcmd)
static void tc_mesh_customdata_free_fn(struct TransInfo *t, struct TransDataContainer *tc, struct TransCustomData *custom_data)
void transform_convert_mesh_crazyspace_free(struct TransMeshDataCrazySpace *r_crazyspace_data)
static struct TransCustomDataLayer * tc_mesh_customdatacorrect_create_impl(TransDataContainer *tc, const bool use_merge_group)
void transform_convert_mesh_crazyspace_detect(TransInfo *t, struct TransDataContainer *tc, struct BMEditMesh *em, struct TransMeshDataCrazySpace *r_crazyspace_data)
void transform_convert_mesh_customdatacorrect_init(TransInfo *t)
static void tc_mesh_customdatacorrect_face_substitute_set(struct TransCustomDataLayer *tcld, BMFace *f, BMFace *f_copy)
static void tc_mesh_transdata_mirror_apply(TransDataContainer *tc)
static BMFace * tc_mesh_customdatacorrect_find_best_face_substitute(BMFace *f)
#define TRANSFORM_MAXDIST_MIRROR
static void tc_mesh_partial_types_calc(TransInfo *t, struct PartialTypeState *r_partial_state)
static struct TransCustomDataMesh * tc_mesh_customdata_ensure(TransDataContainer *tc)
void transform_convert_mesh_crazyspace_transdata_set(const float mtx[3][3], const float smtx[3][3], const float defmat[3][3], const float quat[4], struct TransData *r_td)
static void tc_mesh_customdatacorrect_apply(TransDataContainer *tc, bool is_final)
static void tc_mesh_customdatacorrect_apply_vert(struct TransCustomDataLayer *tcld, struct TransDataBasic *td, struct TransCustomDataMergeGroup *merge_data, bool do_loop_mdisps)
static const float * tc_mesh_vert_orig_co_get(struct TransCustomDataLayer *tcld, BMVert *v)
void transform_convert_mesh_islands_calc(struct BMEditMesh *em, const bool calc_single_islands, const bool calc_island_center, const bool calc_island_axismtx, struct TransIslandData *r_island_data)
static void tc_mesh_customdatacorrect_init_container_generic(TransDataContainer *UNUSED(tc), struct TransCustomDataLayer *tcld)
#define PARTIAL_TYPE_MAX
static void tc_mesh_customdatacorrect_restore(struct TransInfo *t)
static void createTransEditVerts(bContext *UNUSED(C), TransInfo *t)
static BMFace * tc_mesh_customdatacorrect_face_substitute_get(BMFace *f_copy)
static BMPartialUpdate * tc_mesh_partial_ensure(TransInfo *t, TransDataContainer *tc, enum ePartialType partial_type)
static void tc_mesh_customdatacorrect_init_container_merge_group(TransDataContainer *tc, struct TransCustomDataLayer *tcld)
void transform_convert_mesh_mirrordata_free(struct TransMirrorData *mirror_data)
static bool bmesh_test_loose_edge(BMEdge *edge)
@ PARTIAL_TYPE_GROUP
@ PARTIAL_TYPE_ALL
@ PARTIAL_NONE
static bool bmesh_test_dist_add(BMVert *v0, BMVert *v1, BMVert *v2, float *dists, int *index, const float mtx[3][3])
static void tc_mesh_customdatacorrect_init_vert(struct TransCustomDataLayer *tcld, struct TransDataBasic *td, const int index)
void special_aftertrans_update__mesh(bContext *UNUSED(C), TransInfo *t)
void transform_convert_mesh_connectivity_distance(struct BMesh *bm, const float mtx[3][3], float *dists, int *index)
static bool is_in_quadrant_v3(const float co[3], const int quadrant[3], const float epsilon)
static void recalcData_mesh(TransInfo *t)
TransConvertTypeInfo TransConvertType_Mesh
static void tc_mesh_partial_update(TransInfo *t, TransDataContainer *tc, const struct PartialTypeState *partial_state)
@ TD_MIRROR_EDGE_Y
@ TD_MIRROR_Z
@ TD_MIRROR_EDGE_Z
@ TD_MIRROR_X
@ TD_NOTCONNECTED
@ TD_MIRROR_Y
@ TD_MIRROR_EDGE_X
@ TD_SELECTED
#define TD_MIRROR_EDGE_AXIS_SHIFT
bool createSpaceNormalTangent(float mat[3][3], const float normal[3], const float tangent[3])
bool createSpaceNormal(float mat[3][3], const float normal[3])
bool usingSnappingNormal(const TransInfo *t)
bool activeSnap_SnappingIndividual(const TransInfo *t)
void applySnappingIndividual(TransInfo *t)
bool validSnappingNormal(const TransInfo *t)
bool activeSnap(const TransInfo *t)