Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/transform/transform_conversions.c
- This file is larger than 256 KB, so syntax highlighting is disabled by default.
| Show First 20 Lines • Show All 42 Lines • ▼ Show 20 Lines | |||||
| #include "DNA_movieclip_types.h" | #include "DNA_movieclip_types.h" | ||||
| #include "DNA_mask_types.h" | #include "DNA_mask_types.h" | ||||
| #include "MEM_guardedalloc.h" | #include "MEM_guardedalloc.h" | ||||
| #include "BLI_math.h" | #include "BLI_math.h" | ||||
| #include "BLI_utildefines.h" | #include "BLI_utildefines.h" | ||||
| #include "BLI_listbase.h" | #include "BLI_listbase.h" | ||||
| #include "BLI_linklist_stack.h" | |||||
| #include "BLI_string.h" | #include "BLI_string.h" | ||||
| #include "BLI_bitmap.h" | #include "BLI_bitmap.h" | ||||
| #include "BLI_rect.h" | #include "BLI_rect.h" | ||||
| #include "BLI_kdtree.h" | #include "BLI_kdtree.h" | ||||
| #include "BKE_action.h" | #include "BKE_action.h" | ||||
| #include "BKE_animsys.h" | #include "BKE_animsys.h" | ||||
| #include "BKE_armature.h" | #include "BKE_armature.h" | ||||
| #include "BKE_constraint.h" | #include "BKE_constraint.h" | ||||
| #include "BKE_context.h" | #include "BKE_context.h" | ||||
| #include "BKE_crazyspace.h" | |||||
| #include "BKE_curve.h" | #include "BKE_curve.h" | ||||
| #include "BKE_fcurve.h" | #include "BKE_fcurve.h" | ||||
| #include "BKE_global.h" | #include "BKE_global.h" | ||||
| #include "BKE_gpencil.h" | #include "BKE_gpencil.h" | ||||
| #include "BKE_layer.h" | #include "BKE_layer.h" | ||||
| #include "BKE_key.h" | #include "BKE_key.h" | ||||
| #include "BKE_main.h" | #include "BKE_main.h" | ||||
| #include "BKE_mesh.h" | #include "BKE_mesh.h" | ||||
| Show All 40 Lines | |||||
| #include "RNA_access.h" | #include "RNA_access.h" | ||||
| #include "DEG_depsgraph.h" | #include "DEG_depsgraph.h" | ||||
| #include "DEG_depsgraph_build.h" | #include "DEG_depsgraph_build.h" | ||||
| #include "DEG_depsgraph_query.h" | #include "DEG_depsgraph_query.h" | ||||
| #include "transform.h" | #include "transform.h" | ||||
| #include "bmesh.h" | #include "transform_conversions.h" | ||||
| /** | /** | ||||
| * Transforming around ourselves is no use, fallback to individual origins, | * Transforming around ourselves is no use, fallback to individual origins, | ||||
| * useful for curve/armatures. | * useful for curve/armatures. | ||||
| */ | */ | ||||
| static void transform_around_single_fallback(TransInfo *t) | static void transform_around_single_fallback(TransInfo *t) | ||||
| { | { | ||||
| if ((t->data_len_all == 1) && | if ((t->data_len_all == 1) && | ||||
| (ELEM(t->around, V3D_AROUND_CENTER_BOUNDS, V3D_AROUND_CENTER_MEDIAN, V3D_AROUND_ACTIVE)) && | (ELEM(t->around, V3D_AROUND_CENTER_BOUNDS, V3D_AROUND_CENTER_MEDIAN, V3D_AROUND_ACTIVE)) && | ||||
| (ELEM(t->mode, TFM_RESIZE, TFM_ROTATION, TFM_TRACKBALL))) { | (ELEM(t->mode, TFM_RESIZE, TFM_ROTATION, TFM_TRACKBALL))) { | ||||
| t->around = V3D_AROUND_LOCAL_ORIGINS; | t->around = V3D_AROUND_LOCAL_ORIGINS; | ||||
| } | } | ||||
| } | } | ||||
| /* when transforming islands */ | |||||
| struct TransIslandData { | |||||
| float co[3]; | |||||
| float axismtx[3][3]; | |||||
| }; | |||||
| /* local function prototype - for Object/Bone Constraints */ | /* local function prototype - for Object/Bone Constraints */ | ||||
| static bool constraints_list_needinv(TransInfo *t, ListBase *list); | static bool constraints_list_needinv(TransInfo *t, ListBase *list); | ||||
| /* ************************** Functions *************************** */ | /* ************************** Functions *************************** */ | ||||
| static int trans_data_compare_dist(const void *a, const void *b) | static int trans_data_compare_dist(const void *a, const void *b) | ||||
| { | { | ||||
| const TransData *td_a = (const TransData *)a; | const TransData *td_a = (const TransData *)a; | ||||
| ▲ Show 20 Lines • Show All 2,460 Lines • ▼ Show 20 Lines | FOREACH_TRANS_DATA_CONTAINER (t, tc) { | ||||
| } | } | ||||
| PE_update_object(t->depsgraph, scene, OBACT(view_layer), 1); | PE_update_object(t->depsgraph, scene, OBACT(view_layer), 1); | ||||
| BKE_particle_batch_cache_dirty_tag(psys, BKE_PARTICLE_BATCH_DIRTY_ALL); | BKE_particle_batch_cache_dirty_tag(psys, BKE_PARTICLE_BATCH_DIRTY_ALL); | ||||
| DEG_id_tag_update(&ob->id, ID_RECALC_PSYS_REDO); | DEG_id_tag_update(&ob->id, ID_RECALC_PSYS_REDO); | ||||
| } | } | ||||
| } | } | ||||
| /* ********************* mesh ****************** */ | |||||
| static bool bmesh_test_dist_add(BMVert *v, | |||||
| BMVert *v_other, | |||||
| float *dists, | |||||
| const float *dists_prev, | |||||
| /* optionally track original index */ | |||||
| int *index, | |||||
| const int *index_prev, | |||||
| float mtx[3][3]) | |||||
| { | |||||
| if ((BM_elem_flag_test(v_other, BM_ELEM_SELECT) == 0) && | |||||
| (BM_elem_flag_test(v_other, BM_ELEM_HIDDEN) == 0)) { | |||||
| const int i = BM_elem_index_get(v); | |||||
| const int i_other = BM_elem_index_get(v_other); | |||||
| float vec[3]; | |||||
| float dist_other; | |||||
| sub_v3_v3v3(vec, v->co, v_other->co); | |||||
| mul_m3_v3(mtx, vec); | |||||
| dist_other = dists_prev[i] + len_v3(vec); | |||||
| if (dist_other < dists[i_other]) { | |||||
| dists[i_other] = dist_other; | |||||
| if (index != NULL) { | |||||
| index[i_other] = index_prev[i]; | |||||
| } | |||||
| return true; | |||||
| } | |||||
| } | |||||
| return false; | |||||
| } | |||||
| /** | |||||
| * \param mtx: Measure distance in this space. | |||||
| * \param dists: Store the closest connected distance to selected vertices. | |||||
| * \param index: Optionally store the original index we're measuring the distance to (can be NULL). | |||||
| */ | |||||
| static void editmesh_set_connectivity_distance(BMesh *bm, | |||||
| float mtx[3][3], | |||||
| float *dists, | |||||
| int *index) | |||||
| { | |||||
| BLI_LINKSTACK_DECLARE(queue, BMVert *); | |||||
| /* any BM_ELEM_TAG'd vertex is in 'queue_next', so we don't add in twice */ | |||||
| BLI_LINKSTACK_DECLARE(queue_next, BMVert *); | |||||
| BLI_LINKSTACK_INIT(queue); | |||||
| BLI_LINKSTACK_INIT(queue_next); | |||||
| { | |||||
| BMIter viter; | |||||
| BMVert *v; | |||||
| int i; | |||||
| BM_ITER_MESH_INDEX (v, &viter, bm, BM_VERTS_OF_MESH, i) { | |||||
| float dist; | |||||
| BM_elem_index_set(v, i); /* set_inline */ | |||||
| BM_elem_flag_disable(v, BM_ELEM_TAG); | |||||
| if (BM_elem_flag_test(v, BM_ELEM_SELECT) == 0 || BM_elem_flag_test(v, BM_ELEM_HIDDEN)) { | |||||
| dist = FLT_MAX; | |||||
| if (index != NULL) { | |||||
| index[i] = i; | |||||
| } | |||||
| } | |||||
| else { | |||||
| BLI_LINKSTACK_PUSH(queue, v); | |||||
| dist = 0.0f; | |||||
| if (index != NULL) { | |||||
| index[i] = i; | |||||
| } | |||||
| } | |||||
| dists[i] = dist; | |||||
| } | |||||
| bm->elem_index_dirty &= ~BM_VERT; | |||||
| } | |||||
| /* need to be very careful of feedback loops here, store previous dist's to avoid feedback */ | |||||
| float *dists_prev = MEM_dupallocN(dists); | |||||
| int *index_prev = MEM_dupallocN(index); /* may be NULL */ | |||||
| do { | |||||
| BMVert *v; | |||||
| LinkNode *lnk; | |||||
| /* this is correct but slow to do each iteration, | |||||
| * instead sync the dist's while clearing BM_ELEM_TAG (below) */ | |||||
| #if 0 | |||||
| memcpy(dists_prev, dists, sizeof(float) * bm->totvert); | |||||
| #endif | |||||
| while ((v = BLI_LINKSTACK_POP(queue))) { | |||||
| BLI_assert(dists[BM_elem_index_get(v)] != FLT_MAX); | |||||
| /* connected edge-verts */ | |||||
| if (v->e != NULL) { | |||||
| BMEdge *e_iter, *e_first; | |||||
| e_iter = e_first = v->e; | |||||
| /* would normally use BM_EDGES_OF_VERT, but this runs so often, | |||||
| * its faster to iterate on the data directly */ | |||||
| do { | |||||
| if (BM_elem_flag_test(e_iter, BM_ELEM_HIDDEN) == 0) { | |||||
| /* edge distance */ | |||||
| { | |||||
| BMVert *v_other = BM_edge_other_vert(e_iter, v); | |||||
| if (bmesh_test_dist_add(v, v_other, dists, dists_prev, index, index_prev, mtx)) { | |||||
| if (BM_elem_flag_test(v_other, BM_ELEM_TAG) == 0) { | |||||
| BM_elem_flag_enable(v_other, BM_ELEM_TAG); | |||||
| BLI_LINKSTACK_PUSH(queue_next, v_other); | |||||
| } | |||||
| } | |||||
| } | |||||
| /* face distance */ | |||||
| if (e_iter->l) { | |||||
| BMLoop *l_iter_radial, *l_first_radial; | |||||
| /** | |||||
| * imaginary edge diagonally across quad, | |||||
| * \note, this takes advantage of the rules of winding that we | |||||
| * know 2 or more of a verts edges wont reference the same face twice. | |||||
| * Also, if the edge is hidden, the face will be hidden too. | |||||
| */ | |||||
| l_iter_radial = l_first_radial = e_iter->l; | |||||
| do { | |||||
| if ((l_iter_radial->v == v) && (l_iter_radial->f->len == 4) && | |||||
| (BM_elem_flag_test(l_iter_radial->f, BM_ELEM_HIDDEN) == 0)) { | |||||
| BMVert *v_other = l_iter_radial->next->next->v; | |||||
| if (bmesh_test_dist_add(v, v_other, dists, dists_prev, index, index_prev, mtx)) { | |||||
| if (BM_elem_flag_test(v_other, BM_ELEM_TAG) == 0) { | |||||
| BM_elem_flag_enable(v_other, BM_ELEM_TAG); | |||||
| BLI_LINKSTACK_PUSH(queue_next, v_other); | |||||
| } | |||||
| } | |||||
| } | |||||
| } while ((l_iter_radial = l_iter_radial->radial_next) != l_first_radial); | |||||
| } | |||||
| } | |||||
| } while ((e_iter = BM_DISK_EDGE_NEXT(e_iter, v)) != e_first); | |||||
| } | |||||
| } | |||||
| /* clear for the next loop */ | |||||
| for (lnk = queue_next; lnk; lnk = lnk->next) { | |||||
| BMVert *v_link = lnk->link; | |||||
| const int i = BM_elem_index_get(v_link); | |||||
| BM_elem_flag_disable(v_link, BM_ELEM_TAG); | |||||
| /* keep in sync, avoid having to do full memcpy each iteration */ | |||||
| dists_prev[i] = dists[i]; | |||||
| if (index != NULL) { | |||||
| index_prev[i] = index[i]; | |||||
| } | |||||
| } | |||||
| BLI_LINKSTACK_SWAP(queue, queue_next); | |||||
| /* none should be tagged now since 'queue_next' is empty */ | |||||
| BLI_assert(BM_iter_mesh_count_flag(BM_VERTS_OF_MESH, bm, BM_ELEM_TAG, true) == 0); | |||||
| } while (BLI_LINKSTACK_SIZE(queue)); | |||||
| BLI_LINKSTACK_FREE(queue); | |||||
| BLI_LINKSTACK_FREE(queue_next); | |||||
| MEM_freeN(dists_prev); | |||||
| if (index_prev != NULL) { | |||||
| MEM_freeN(index_prev); | |||||
| } | |||||
| } | |||||
| static struct TransIslandData *editmesh_islands_info_calc(BMEditMesh *em, | |||||
| int *r_island_tot, | |||||
| int **r_island_vert_map, | |||||
| bool calc_single_islands) | |||||
| { | |||||
| BMesh *bm = em->bm; | |||||
| struct TransIslandData *trans_islands; | |||||
| char htype; | |||||
| char itype; | |||||
| int i; | |||||
| /* group vars */ | |||||
| int *groups_array; | |||||
| int(*group_index)[2]; | |||||
| int group_tot; | |||||
| void **ele_array; | |||||
| int *vert_map; | |||||
| if (em->selectmode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE)) { | |||||
| groups_array = MEM_mallocN(sizeof(*groups_array) * bm->totedgesel, __func__); | |||||
| group_tot = BM_mesh_calc_edge_groups( | |||||
| bm, groups_array, &group_index, NULL, NULL, BM_ELEM_SELECT); | |||||
| htype = BM_EDGE; | |||||
| itype = BM_VERTS_OF_EDGE; | |||||
| } | |||||
| else { /* (bm->selectmode & SCE_SELECT_FACE) */ | |||||
| groups_array = MEM_mallocN(sizeof(*groups_array) * bm->totfacesel, __func__); | |||||
| group_tot = BM_mesh_calc_face_groups( | |||||
| bm, groups_array, &group_index, NULL, NULL, BM_ELEM_SELECT, BM_VERT); | |||||
| htype = BM_FACE; | |||||
| itype = BM_VERTS_OF_FACE; | |||||
| } | |||||
| trans_islands = MEM_mallocN(sizeof(*trans_islands) * group_tot, __func__); | |||||
| vert_map = MEM_mallocN(sizeof(*vert_map) * bm->totvert, __func__); | |||||
| /* we shouldn't need this, but with incorrect selection flushing | |||||
| * its possible we have a selected vertex that's not in a face, | |||||
| * for now best not crash in that case. */ | |||||
| copy_vn_i(vert_map, bm->totvert, -1); | |||||
| BM_mesh_elem_table_ensure(bm, htype); | |||||
| ele_array = (htype == BM_FACE) ? (void **)bm->ftable : (void **)bm->etable; | |||||
| BM_mesh_elem_index_ensure(bm, BM_VERT); | |||||
| /* may be an edge OR a face array */ | |||||
| for (i = 0; i < group_tot; i++) { | |||||
| BMEditSelection ese = {NULL}; | |||||
| const int fg_sta = group_index[i][0]; | |||||
| const int fg_len = group_index[i][1]; | |||||
| float co[3], no[3], tangent[3]; | |||||
| int j; | |||||
| zero_v3(co); | |||||
| zero_v3(no); | |||||
| zero_v3(tangent); | |||||
| ese.htype = htype; | |||||
| /* loop on each face in this group: | |||||
| * - assign r_vert_map | |||||
| * - calculate (co, no) | |||||
| */ | |||||
| for (j = 0; j < fg_len; j++) { | |||||
| float tmp_co[3], tmp_no[3], tmp_tangent[3]; | |||||
| ese.ele = ele_array[groups_array[fg_sta + j]]; | |||||
| BM_editselection_center(&ese, tmp_co); | |||||
| BM_editselection_normal(&ese, tmp_no); | |||||
| BM_editselection_plane(&ese, tmp_tangent); | |||||
| add_v3_v3(co, tmp_co); | |||||
| add_v3_v3(no, tmp_no); | |||||
| add_v3_v3(tangent, tmp_tangent); | |||||
| { | |||||
| /* setup vertex map */ | |||||
| BMIter iter; | |||||
| BMVert *v; | |||||
| /* connected edge-verts */ | |||||
| BM_ITER_ELEM (v, &iter, ese.ele, itype) { | |||||
| vert_map[BM_elem_index_get(v)] = i; | |||||
| } | |||||
| } | |||||
| } | |||||
| mul_v3_v3fl(trans_islands[i].co, co, 1.0f / (float)fg_len); | |||||
| if (createSpaceNormalTangent(trans_islands[i].axismtx, no, tangent)) { | |||||
| /* pass */ | |||||
| } | |||||
| else { | |||||
| if (normalize_v3(no) != 0.0f) { | |||||
| axis_dominant_v3_to_m3(trans_islands[i].axismtx, no); | |||||
| invert_m3(trans_islands[i].axismtx); | |||||
| } | |||||
| else { | |||||
| unit_m3(trans_islands[i].axismtx); | |||||
| } | |||||
| } | |||||
| } | |||||
| MEM_freeN(groups_array); | |||||
| MEM_freeN(group_index); | |||||
| /* for PET we need islands of 1 so connected vertices can use it with V3D_AROUND_LOCAL_ORIGINS */ | |||||
| if (calc_single_islands) { | |||||
| BMIter viter; | |||||
| BMVert *v; | |||||
| int group_tot_single = 0; | |||||
| BM_ITER_MESH_INDEX (v, &viter, bm, BM_VERTS_OF_MESH, i) { | |||||
| if (BM_elem_flag_test(v, BM_ELEM_SELECT) && (vert_map[i] == -1)) { | |||||
| group_tot_single += 1; | |||||
| } | |||||
| } | |||||
| if (group_tot_single != 0) { | |||||
| trans_islands = MEM_reallocN(trans_islands, | |||||
| sizeof(*trans_islands) * (group_tot + group_tot_single)); | |||||
| BM_ITER_MESH_INDEX (v, &viter, bm, BM_VERTS_OF_MESH, i) { | |||||
| if (BM_elem_flag_test(v, BM_ELEM_SELECT) && (vert_map[i] == -1)) { | |||||
| struct TransIslandData *v_island = &trans_islands[group_tot]; | |||||
| vert_map[i] = group_tot; | |||||
| copy_v3_v3(v_island->co, v->co); | |||||
| if (is_zero_v3(v->no) != 0.0f) { | |||||
| axis_dominant_v3_to_m3(v_island->axismtx, v->no); | |||||
| invert_m3(v_island->axismtx); | |||||
| } | |||||
| else { | |||||
| unit_m3(v_island->axismtx); | |||||
| } | |||||
| group_tot += 1; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| *r_island_tot = group_tot; | |||||
| *r_island_vert_map = vert_map; | |||||
| return trans_islands; | |||||
| } | |||||
| /* way to overwrite what data is edited with transform */ | |||||
| static void VertsToTransData(TransInfo *t, | |||||
| TransData *td, | |||||
| TransDataExtension *tx, | |||||
| BMEditMesh *em, | |||||
| BMVert *eve, | |||||
| float *bweight, | |||||
| struct TransIslandData *v_island, | |||||
| const bool no_island_center) | |||||
| { | |||||
| float *no, _no[3]; | |||||
| BLI_assert(BM_elem_flag_test(eve, BM_ELEM_HIDDEN) == 0); | |||||
| td->flag = 0; | |||||
| // if (key) | |||||
| // td->loc = key->co; | |||||
| // else | |||||
| td->loc = eve->co; | |||||
| copy_v3_v3(td->iloc, td->loc); | |||||
| if ((t->mode == TFM_SHRINKFATTEN) && (em->selectmode & SCE_SELECT_FACE) && | |||||
| BM_elem_flag_test(eve, BM_ELEM_SELECT) && | |||||
| (BM_vert_calc_normal_ex(eve, BM_ELEM_SELECT, _no))) { | |||||
| no = _no; | |||||
| } | |||||
| else { | |||||
| no = eve->no; | |||||
| } | |||||
| if (v_island) { | |||||
| if (no_island_center) { | |||||
| copy_v3_v3(td->center, td->loc); | |||||
| } | |||||
| else { | |||||
| copy_v3_v3(td->center, v_island->co); | |||||
| } | |||||
| copy_m3_m3(td->axismtx, v_island->axismtx); | |||||
| } | |||||
| else if (t->around == V3D_AROUND_LOCAL_ORIGINS) { | |||||
| copy_v3_v3(td->center, td->loc); | |||||
| createSpaceNormal(td->axismtx, no); | |||||
| } | |||||
| else { | |||||
| copy_v3_v3(td->center, td->loc); | |||||
| /* Setting normals */ | |||||
| copy_v3_v3(td->axismtx[2], no); | |||||
| td->axismtx[0][0] = td->axismtx[0][1] = td->axismtx[0][2] = td->axismtx[1][0] = | |||||
| td->axismtx[1][1] = td->axismtx[1][2] = 0.0f; | |||||
| } | |||||
| td->ext = NULL; | |||||
| td->val = NULL; | |||||
| td->extra = NULL; | |||||
| if (t->mode == TFM_BWEIGHT) { | |||||
| td->val = bweight; | |||||
| td->ival = *bweight; | |||||
| } | |||||
| else if (t->mode == TFM_SKIN_RESIZE) { | |||||
| MVertSkin *vs = CustomData_bmesh_get(&em->bm->vdata, eve->head.data, CD_MVERT_SKIN); | |||||
| if (vs) { | |||||
| /* skin node size */ | |||||
| td->ext = tx; | |||||
| copy_v3_v3(tx->isize, vs->radius); | |||||
| tx->size = vs->radius; | |||||
| td->val = vs->radius; | |||||
| } | |||||
| else { | |||||
| td->flag |= TD_SKIP; | |||||
| } | |||||
| } | |||||
| else if (t->mode == TFM_SHRINKFATTEN) { | |||||
| td->ext = tx; | |||||
| tx->isize[0] = BM_vert_calc_shell_factor_ex(eve, no, BM_ELEM_SELECT); | |||||
| } | |||||
| } | |||||
| static void createTransEditVerts(TransInfo *t) | |||||
| { | |||||
| FOREACH_TRANS_DATA_CONTAINER (t, tc) { | |||||
| TransData *tob = NULL; | |||||
| TransDataExtension *tx = NULL; | |||||
| BMEditMesh *em = BKE_editmesh_from_object(tc->obedit); | |||||
| Mesh *me = tc->obedit->data; | |||||
| BMesh *bm = em->bm; | |||||
| BMVert *eve; | |||||
| BMIter iter; | |||||
| float(*mappedcos)[3] = NULL, (*quats)[4] = NULL; | |||||
| float mtx[3][3], smtx[3][3], (*defmats)[3][3] = NULL, (*defcos)[3] = NULL; | |||||
| float *dists = NULL; | |||||
| int a; | |||||
| const int prop_mode = (t->flag & T_PROP_EDIT) ? (t->flag & T_PROP_EDIT_ALL) : 0; | |||||
| int mirror = 0; | |||||
| int cd_vert_bweight_offset = -1; | |||||
| bool use_topology = (me->editflag & ME_EDIT_MIRROR_TOPO) != 0; | |||||
| struct TransIslandData *island_info = NULL; | |||||
| int island_info_tot; | |||||
| int *island_vert_map = NULL; | |||||
| /* Snap rotation along normal needs a common axis for whole islands, | |||||
| * otherwise one get random crazy results, see T59104. | |||||
| * However, we do not want to use the island center for the pivot/translation reference. */ | |||||
| const bool is_snap_rotate = ((t->mode == TFM_TRANSLATION) && | |||||
| /* There is not guarantee that snapping | |||||
| * is initialized yet at this point... */ | |||||
| (usingSnappingNormal(t) || | |||||
| (t->settings->snap_flag & SCE_SNAP_ROTATE) != 0) && | |||||
| (t->around != V3D_AROUND_LOCAL_ORIGINS)); | |||||
| /* Even for translation this is needed because of island-orientation, see: T51651. */ | |||||
| const bool is_island_center = (t->around == V3D_AROUND_LOCAL_ORIGINS) || is_snap_rotate; | |||||
| /* Original index of our connected vertex when connected distances are calculated. | |||||
| * Optional, allocate if needed. */ | |||||
| int *dists_index = NULL; | |||||
| if (tc->mirror.axis_flag) { | |||||
| EDBM_verts_mirror_cache_begin(em, 0, false, (t->flag & T_PROP_EDIT) == 0, use_topology); | |||||
| mirror = 1; | |||||
| } | |||||
| /** | |||||
| * Quick check if we can transform. | |||||
| * | |||||
| * \note ignore modes here, even in edge/face modes, | |||||
| * transform data is created by selected vertices. | |||||
| * \note in prop mode we need at least 1 selected. | |||||
| */ | |||||
| if (bm->totvertsel == 0) { | |||||
| goto cleanup; | |||||
| } | |||||
| if (t->mode == TFM_BWEIGHT) { | |||||
| BM_mesh_cd_flag_ensure(bm, BKE_mesh_from_object(tc->obedit), ME_CDFLAG_VERT_BWEIGHT); | |||||
| cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT); | |||||
| } | |||||
| if (prop_mode) { | |||||
| unsigned int count = 0; | |||||
| BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) { | |||||
| if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) { | |||||
| count++; | |||||
| } | |||||
| } | |||||
| tc->data_len = count; | |||||
| /* allocating scratch arrays */ | |||||
| if (prop_mode & T_PROP_CONNECTED) { | |||||
| dists = MEM_mallocN(em->bm->totvert * sizeof(float), __func__); | |||||
| if (is_island_center) { | |||||
| dists_index = MEM_mallocN(em->bm->totvert * sizeof(int), __func__); | |||||
| } | |||||
| } | |||||
| } | |||||
| else { | |||||
| tc->data_len = bm->totvertsel; | |||||
| } | |||||
| tob = tc->data = MEM_callocN(tc->data_len * sizeof(TransData), "TransObData(Mesh EditMode)"); | |||||
| if (ELEM(t->mode, TFM_SKIN_RESIZE, TFM_SHRINKFATTEN)) { | |||||
| /* warning, this is overkill, we only need 2 extra floats, | |||||
| * but this stores loads of extra stuff, for TFM_SHRINKFATTEN its even more overkill | |||||
| * since we may not use the 'alt' transform mode to maintain shell thickness, | |||||
| * but with generic transform code its hard to lazy init vars */ | |||||
| tx = tc->data_ext = MEM_callocN(tc->data_len * sizeof(TransDataExtension), | |||||
| "TransObData ext"); | |||||
| } | |||||
| copy_m3_m4(mtx, tc->obedit->obmat); | |||||
| /* we use a pseudo-inverse so that when one of the axes is scaled to 0, | |||||
| * matrix inversion still works and we can still moving along the other */ | |||||
| pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON); | |||||
| if (prop_mode & T_PROP_CONNECTED) { | |||||
| editmesh_set_connectivity_distance(em->bm, mtx, dists, dists_index); | |||||
| } | |||||
| if (is_island_center) { | |||||
| /* In this specific case, near-by vertices will need to know | |||||
| * the island of the nearest connected vertex. */ | |||||
| const bool calc_single_islands = ((prop_mode & T_PROP_CONNECTED) && | |||||
| (t->around == V3D_AROUND_LOCAL_ORIGINS) && | |||||
| (em->selectmode & SCE_SELECT_VERTEX)); | |||||
| island_info = editmesh_islands_info_calc( | |||||
| em, &island_info_tot, &island_vert_map, calc_single_islands); | |||||
| } | |||||
| /* detect CrazySpace [tm] */ | |||||
| if (modifiers_getCageIndex(t->scene, tc->obedit, NULL, 1) != -1) { | |||||
| int totleft = -1; | |||||
| if (modifiers_isCorrectableDeformed(t->scene, tc->obedit)) { | |||||
| BKE_scene_graph_evaluated_ensure(t->depsgraph, CTX_data_main(t->context)); | |||||
| /* Use evaluated state because we need b-bone cache. */ | |||||
| Scene *scene_eval = (Scene *)DEG_get_evaluated_id(t->depsgraph, &t->scene->id); | |||||
| Object *obedit_eval = (Object *)DEG_get_evaluated_id(t->depsgraph, &tc->obedit->id); | |||||
| BMEditMesh *em_eval = BKE_editmesh_from_object(obedit_eval); | |||||
| /* check if we can use deform matrices for modifier from the | |||||
| * start up to stack, they are more accurate than quats */ | |||||
| totleft = BKE_crazyspace_get_first_deform_matrices_editbmesh( | |||||
| t->depsgraph, scene_eval, obedit_eval, em_eval, &defmats, &defcos); | |||||
| } | |||||
| /* if we still have more modifiers, also do crazyspace | |||||
| * correction with quats, relative to the coordinates after | |||||
| * the modifiers that support deform matrices (defcos) */ | |||||
| #if 0 /* TODO, fix crazyspace+extrude so it can be enabled for general use - campbell */ | |||||
| if ((totleft > 0) || (totleft == -1)) | |||||
| #else | |||||
| if (totleft > 0) | |||||
| #endif | |||||
| { | |||||
| mappedcos = BKE_crazyspace_get_mapped_editverts(t->depsgraph, tc->obedit); | |||||
| quats = MEM_mallocN(em->bm->totvert * sizeof(*quats), "crazy quats"); | |||||
| BKE_crazyspace_set_quats_editmesh(em, defcos, mappedcos, quats, !prop_mode); | |||||
| if (mappedcos) { | |||||
| MEM_freeN(mappedcos); | |||||
| } | |||||
| } | |||||
| if (defcos) { | |||||
| MEM_freeN(defcos); | |||||
| } | |||||
| } | |||||
| /* find out which half we do */ | |||||
| if (mirror) { | |||||
| BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) { | |||||
| if (BM_elem_flag_test(eve, BM_ELEM_SELECT) && eve->co[0] != 0.0f) { | |||||
| if (eve->co[0] < 0.0f) { | |||||
| tc->mirror.sign = -1.0f; | |||||
| mirror = -1; | |||||
| } | |||||
| break; | |||||
| } | |||||
| } | |||||
| } | |||||
| BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, a) { | |||||
| if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) { | |||||
| if (prop_mode || BM_elem_flag_test(eve, BM_ELEM_SELECT)) { | |||||
| struct TransIslandData *v_island = NULL; | |||||
| float *bweight = (cd_vert_bweight_offset != -1) ? | |||||
| BM_ELEM_CD_GET_VOID_P(eve, cd_vert_bweight_offset) : | |||||
| NULL; | |||||
| if (island_info) { | |||||
| const int connected_index = (dists_index && dists_index[a] != -1) ? dists_index[a] : a; | |||||
| v_island = (island_vert_map[connected_index] != -1) ? | |||||
| &island_info[island_vert_map[connected_index]] : | |||||
| NULL; | |||||
| } | |||||
| /* Do not use the island center in case we are using islands | |||||
| * only to get axis for snap/rotate to normal... */ | |||||
| VertsToTransData(t, tob, tx, em, eve, bweight, v_island, is_snap_rotate); | |||||
| if (tx) { | |||||
| tx++; | |||||
| } | |||||
| /* selected */ | |||||
| if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) { | |||||
| tob->flag |= TD_SELECTED; | |||||
| } | |||||
| if (prop_mode) { | |||||
| if (prop_mode & T_PROP_CONNECTED) { | |||||
| tob->dist = dists[a]; | |||||
| } | |||||
| else { | |||||
| tob->flag |= TD_NOTCONNECTED; | |||||
| tob->dist = FLT_MAX; | |||||
| } | |||||
| } | |||||
| /* CrazySpace */ | |||||
| const bool use_quats = quats && BM_elem_flag_test(eve, BM_ELEM_TAG); | |||||
| if (use_quats || defmats) { | |||||
| float mat[3][3], qmat[3][3], imat[3][3]; | |||||
| /* Use both or either quat and defmat correction. */ | |||||
| if (use_quats) { | |||||
| quat_to_mat3(qmat, quats[BM_elem_index_get(eve)]); | |||||
| if (defmats) { | |||||
| mul_m3_series(mat, defmats[a], qmat, mtx); | |||||
| } | |||||
| else { | |||||
| mul_m3_m3m3(mat, mtx, qmat); | |||||
| } | |||||
| } | |||||
| else { | |||||
| mul_m3_m3m3(mat, mtx, defmats[a]); | |||||
| } | |||||
| invert_m3_m3(imat, mat); | |||||
| copy_m3_m3(tob->smtx, imat); | |||||
| copy_m3_m3(tob->mtx, mat); | |||||
| } | |||||
| else { | |||||
| copy_m3_m3(tob->smtx, smtx); | |||||
| copy_m3_m3(tob->mtx, mtx); | |||||
| } | |||||
| /* Mirror? */ | |||||
| if ((mirror > 0 && tob->iloc[0] > 0.0f) || (mirror < 0 && tob->iloc[0] < 0.0f)) { | |||||
| BMVert *vmir = EDBM_verts_mirror_get(em, eve); // t->obedit, em, eve, tob->iloc, a); | |||||
| if (vmir && vmir != eve) { | |||||
| tob->extra = vmir; | |||||
| } | |||||
| } | |||||
| tob++; | |||||
| } | |||||
| } | |||||
| } | |||||
| if (island_info) { | |||||
| MEM_freeN(island_info); | |||||
| MEM_freeN(island_vert_map); | |||||
| } | |||||
| if (mirror != 0) { | |||||
| tob = tc->data; | |||||
| for (a = 0; a < tc->data_len; a++, tob++) { | |||||
| if (ABS(tob->loc[0]) <= 0.00001f) { | |||||
| tob->flag |= TD_MIRROR_EDGE; | |||||
| } | |||||
| } | |||||
| } | |||||
| cleanup: | |||||
| /* crazy space free */ | |||||
| if (quats) { | |||||
| MEM_freeN(quats); | |||||
| } | |||||
| if (defmats) { | |||||
| MEM_freeN(defmats); | |||||
| } | |||||
| if (dists) { | |||||
| MEM_freeN(dists); | |||||
| } | |||||
| if (dists_index) { | |||||
| MEM_freeN(dists_index); | |||||
| } | |||||
| if (tc->mirror.axis_flag) { | |||||
| EDBM_verts_mirror_cache_end(em); | |||||
| } | |||||
| } | |||||
| } | |||||
| /* *** NODE EDITOR *** */ | /* *** NODE EDITOR *** */ | ||||
| void flushTransNodes(TransInfo *t) | void flushTransNodes(TransInfo *t) | ||||
| { | { | ||||
| const float dpi_fac = UI_DPI_FAC; | const float dpi_fac = UI_DPI_FAC; | ||||
| FOREACH_TRANS_DATA_CONTAINER (t, tc) { | FOREACH_TRANS_DATA_CONTAINER (t, tc) { | ||||
| int a; | int a; | ||||
| TransData *td; | TransData *td; | ||||
| ▲ Show 20 Lines • Show All 6,894 Lines • Show Last 20 Lines | |||||