diff options
-rw-r--r-- | source/blender/editors/mesh/editmesh_knife.c | 368 |
1 files changed, 185 insertions, 183 deletions
diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c index 39d104cdcce..7972459e457 100644 --- a/source/blender/editors/mesh/editmesh_knife.c +++ b/source/blender/editors/mesh/editmesh_knife.c @@ -377,45 +377,45 @@ static void knifetool_raycast_planes(const KnifeTool_OpData *kcd, float r_v1[3], kcd->vc.rv3d->persmat, planes[2], planes[0], planes[1], planes[3], NULL, NULL); /* Ray-cast all planes. */ + float ray_dir[3]; + float ray_hit_best[2][3] = {{UNPACK3(kcd->prev.cage)}, {UNPACK3(kcd->curr.cage)}}; + float lambda_best[2] = {-FLT_MAX, FLT_MAX}; + int i; + { - float ray_dir[3]; - float ray_hit_best[2][3] = {{UNPACK3(kcd->prev.cage)}, {UNPACK3(kcd->curr.cage)}}; - float lambda_best[2] = {-FLT_MAX, FLT_MAX}; - int i; + float curr_cage_adjust[3]; + float co_depth[3]; - { - float curr_cage_adjust[3]; - float co_depth[3]; + copy_v3_v3(co_depth, kcd->prev.cage); + ED_view3d_win_to_3d(kcd->vc.v3d, kcd->region, co_depth, kcd->curr.mval, curr_cage_adjust); - copy_v3_v3(co_depth, kcd->prev.cage); - ED_view3d_win_to_3d(kcd->vc.v3d, kcd->region, co_depth, kcd->curr.mval, curr_cage_adjust); + sub_v3_v3v3(ray_dir, curr_cage_adjust, kcd->prev.cage); + } - sub_v3_v3v3(ray_dir, curr_cage_adjust, kcd->prev.cage); + for (i = 0; i < 4; i++) { + float ray_hit[3]; + float lambda_test; + if (!isect_ray_plane_v3(kcd->prev.cage, ray_dir, planes[i], &lambda_test, false)) { + continue; } - for (i = 0; i < 4; i++) { - float ray_hit[3]; - float lambda_test; - if (isect_ray_plane_v3(kcd->prev.cage, ray_dir, planes[i], &lambda_test, false)) { - madd_v3_v3v3fl(ray_hit, kcd->prev.cage, ray_dir, lambda_test); - if (lambda_test < 0.0f) { - if (lambda_test > lambda_best[0]) { - copy_v3_v3(ray_hit_best[0], ray_hit); - lambda_best[0] = lambda_test; - } - } - else { - if (lambda_test < lambda_best[1]) { - copy_v3_v3(ray_hit_best[1], ray_hit); - lambda_best[1] = lambda_test; - } - } + madd_v3_v3v3fl(ray_hit, kcd->prev.cage, ray_dir, lambda_test); + if (lambda_test < 0.0f) { + if (lambda_test > lambda_best[0]) { + copy_v3_v3(ray_hit_best[0], ray_hit); + lambda_best[0] = lambda_test; + } + } + else { + if (lambda_test < lambda_best[1]) { + copy_v3_v3(ray_hit_best[1], ray_hit); + lambda_best[1] = lambda_test; } } - - copy_v3_v3(r_v1, ray_hit_best[0]); - copy_v3_v3(r_v2, ray_hit_best[1]); } + + copy_v3_v3(r_v1, ray_hit_best[0]); + copy_v3_v3(r_v2, ray_hit_best[1]); } static void knifetool_draw_angle_snapping(const KnifeTool_OpData *kcd) @@ -440,43 +440,45 @@ static void knifetool_draw_angle_snapping(const KnifeTool_OpData *kcd) static void knifetool_draw_orientation_locking(const KnifeTool_OpData *kcd) { - if (!compare_v3v3(kcd->prev.cage, kcd->curr.cage, KNIFE_FLT_EPSBIG)) { - float v1[3], v2[3]; + if (compare_v3v3(kcd->prev.cage, kcd->curr.cage, KNIFE_FLT_EPSBIG)) { + return; + } - /* This is causing buggy behavior when `prev.cage` and `curr.cage` are too close together. */ - knifetool_raycast_planes(kcd, v1, v2); + float v1[3], v2[3]; - uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + /* This is causing buggy behavior when `prev.cage` and `curr.cage` are too close together. */ + knifetool_raycast_planes(kcd, v1, v2); - switch (kcd->constrain_axis) { - case KNF_CONSTRAIN_AXIS_X: { - immUniformColor3ubv(kcd->colors.xaxis); - break; - } - case KNF_CONSTRAIN_AXIS_Y: { - immUniformColor3ubv(kcd->colors.yaxis); - break; - } - case KNF_CONSTRAIN_AXIS_Z: { - immUniformColor3ubv(kcd->colors.zaxis); - break; - } - default: { - immUniformColor3ubv(kcd->colors.axis_extra); - break; - } + uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + + switch (kcd->constrain_axis) { + case KNF_CONSTRAIN_AXIS_X: { + immUniformColor3ubv(kcd->colors.xaxis); + break; + } + case KNF_CONSTRAIN_AXIS_Y: { + immUniformColor3ubv(kcd->colors.yaxis); + break; + } + case KNF_CONSTRAIN_AXIS_Z: { + immUniformColor3ubv(kcd->colors.zaxis); + break; } + default: { + immUniformColor3ubv(kcd->colors.axis_extra); + break; + } + } - GPU_line_width(2.0); + GPU_line_width(2.0); - immBegin(GPU_PRIM_LINES, 2); - immVertex3fv(pos, v1); - immVertex3fv(pos, v2); - immEnd(); + immBegin(GPU_PRIM_LINES, 2); + immVertex3fv(pos, v1); + immVertex3fv(pos, v2); + immEnd(); - immUnbindProgram(); - } + immUnbindProgram(); } static void knifetool_draw_visible_distances(const KnifeTool_OpData *kcd) @@ -1226,7 +1228,6 @@ static void knife_bvh_init(KnifeTool_OpData *kcd) } /* Construct BVH Tree. */ - float cos[3][3]; const float epsilon = FLT_EPSILON * 2.0f; int tottri = 0; int ob_tottri = 0; @@ -1283,8 +1284,10 @@ static void knife_bvh_init(KnifeTool_OpData *kcd) if (!test_fn_ret) { continue; } - knife_bm_tri_cagecos_get_worldspace(kcd, b, i, cos); - BLI_bvhtree_insert(kcd->bvh.tree, i + tottri, (float *)cos, 3); + + float tri_cos[3][3]; + knife_bm_tri_cagecos_get_worldspace(kcd, b, i, tri_cos); + BLI_bvhtree_insert(kcd->bvh.tree, i + tottri, &tri_cos[0][0], 3); } tottri += em->tottri; @@ -1307,6 +1310,10 @@ static void knife_bvh_raycast_cb(void *userdata, const BVHTreeRay *ray, BVHTreeRayHit *hit) { + if (index != -1) { + return; + } + KnifeTool_OpData *kcd = userdata; BMLoop **ltri; Object *ob; @@ -1315,60 +1322,49 @@ static void knife_bvh_raycast_cb(void *userdata, float dist, uv[2]; bool isect; int tottri; - float tri_cos[3][3]; - if (index != -1) { - tottri = 0; - uint b = 0; - for (; b < kcd->objects_len; b++) { - index -= tottri; - ob = kcd->objects[b]; - em = BKE_editmesh_from_object(ob); - tottri = em->tottri; - if (index < tottri) { - ltri = em->looptris[index]; - break; - } + tottri = 0; + uint b = 0; + for (; b < kcd->objects_len; b++) { + index -= tottri; + ob = kcd->objects[b]; + em = BKE_editmesh_from_object(ob); + tottri = em->tottri; + if (index < tottri) { + ltri = em->looptris[index]; + break; } + } - if (kcd->bvh.filter_cb) { - if (!kcd->bvh.filter_cb(ltri[0]->f, kcd->bvh.filter_data)) { - return; - } + if (kcd->bvh.filter_cb) { + if (!kcd->bvh.filter_cb(ltri[0]->f, kcd->bvh.filter_data)) { + return; } + } - knife_bm_tri_cagecos_get_worldspace(kcd, b, index, tri_cos); - - isect = - (ray->radius > 0.0f ? - isect_ray_tri_epsilon_v3(ray->origin, - ray->direction, - tri_cos[0], - tri_cos[1], - tri_cos[2], - &dist, - uv, - ray->radius) : + float tri_cos[3][3]; + knife_bm_tri_cagecos_get_worldspace(kcd, b, index, tri_cos); + isect = (ray->radius > 0.0f ? + isect_ray_tri_epsilon_v3( + ray->origin, ray->direction, UNPACK3(tri_cos), &dist, uv, ray->radius) : #ifdef USE_KDOPBVH_WATERTIGHT - isect_ray_tri_watertight_v3( - ray->origin, ray->isect_precalc, tri_cos[0], tri_cos[1], tri_cos[2], &dist, uv)); + isect_ray_tri_watertight_v3( + ray->origin, ray->isect_precalc, UNPACK3(tri_cos), &dist, uv)); #else - isect_ray_tri_v3( - ray->origin, ray->direction, tri_cos[0], tri_cos[1], tri_cos[2], &dist, uv)); + isect_ray_tri_v3(ray->origin, ray->direction, UNPACK3(tri_cos), &dist, uv); #endif - if (isect && dist < hit->dist) { - hit->dist = dist; - hit->index = index; + if (isect && dist < hit->dist) { + hit->dist = dist; + hit->index = index; - copy_v3_v3(hit->no, ltri[0]->f->no); + copy_v3_v3(hit->no, ltri[0]->f->no); - madd_v3_v3v3fl(hit->co, ray->origin, ray->direction, dist); + madd_v3_v3v3fl(hit->co, ray->origin, ray->direction, dist); - kcd->bvh.looptris = em->looptris; - copy_v2_v2(kcd->bvh.uv, uv); - kcd->bvh.base_index = b; - } + kcd->bvh.looptris = em->looptris; + copy_v2_v2(kcd->bvh.uv, uv); + kcd->bvh.base_index = b; } } @@ -1978,29 +1974,30 @@ static void prepare_linehits_for_cut(KnifeTool_OpData *kcd) * Also remove all but one of a series of vertex hits for the same vertex. */ for (int i = 0; i < n; i++) { KnifeLineHit *lhi = &linehits[i]; - if (lhi->v) { - for (int j = i - 1; j >= 0; j--) { - KnifeLineHit *lhj = &linehits[j]; - if (!lhj->kfe || fabsf(lhi->l - lhj->l) > KNIFE_FLT_EPSBIG || - fabsf(lhi->m - lhj->m) > KNIFE_FLT_EPSBIG) { - break; - } + if (lhi->v == NULL) { + continue; + } - if (lhi->kfe == lhj->kfe) { - lhj->l = -1.0f; - is_double = true; - } + for (int j = i - 1; j >= 0; j--) { + KnifeLineHit *lhj = &linehits[j]; + if (!lhj->kfe || fabsf(lhi->l - lhj->l) > KNIFE_FLT_EPSBIG || + fabsf(lhi->m - lhj->m) > KNIFE_FLT_EPSBIG) { + break; } - for (int j = i + 1; j < n; j++) { - KnifeLineHit *lhj = &linehits[j]; - if (fabsf(lhi->l - lhj->l) > KNIFE_FLT_EPSBIG || - fabsf(lhi->m - lhj->m) > KNIFE_FLT_EPSBIG) { - break; - } - if ((lhj->kfe && (lhi->kfe == lhj->kfe)) || (lhi->v == lhj->v)) { - lhj->l = -1.0f; - is_double = true; - } + + if (lhi->kfe == lhj->kfe) { + lhj->l = -1.0f; + is_double = true; + } + } + for (int j = i + 1; j < n; j++) { + KnifeLineHit *lhj = &linehits[j]; + if (fabsf(lhi->l - lhj->l) > KNIFE_FLT_EPSBIG || fabsf(lhi->m - lhj->m) > KNIFE_FLT_EPSBIG) { + break; + } + if ((lhj->kfe && (lhi->kfe == lhj->kfe)) || (lhi->v == lhj->v)) { + lhj->l = -1.0f; + is_double = true; } } } @@ -2272,11 +2269,12 @@ static void knife_make_face_cuts(KnifeTool_OpData *kcd, BMesh *bm, BMFace *f, Li /* Remove dangling edges, not essential - but nice for users. */ for (i = 0; i < edge_array_len_orig; i++) { - if (kfe_array[i]) { - if (BM_edge_is_wire(kfe_array[i]->e)) { - BM_edge_kill(bm, kfe_array[i]->e); - kfe_array[i]->e = NULL; - } + if (kfe_array[i] == NULL) { + continue; + } + if (BM_edge_is_wire(kfe_array[i]->e)) { + BM_edge_kill(bm, kfe_array[i]->e); + kfe_array[i]->e = NULL; } } @@ -2588,7 +2586,7 @@ static bool knife_ray_intersect_face(KnifeTool_OpData *kcd, BLI_assert(tri_i >= 0 && tri_i < tottri); for (; tri_i < tottri; tri_i++) { - float lv[3][3]; + float tri_cos[3][3]; float ray_tri_uv[2]; tri = em->looptris[tri_i]; @@ -2596,22 +2594,22 @@ static bool knife_ray_intersect_face(KnifeTool_OpData *kcd, break; } - knife_bm_tri_cagecos_get_worldspace(kcd, base_index, tri_i, lv); + knife_bm_tri_cagecos_get_worldspace(kcd, base_index, tri_i, tri_cos); /* Using epsilon test in case ray is directly through an internal * tessellation edge and might not hit either tessellation tri with * an exact test; * We will exclude hits near real edges by a later test. */ if (isect_ray_tri_epsilon_v3( - v1, raydir, lv[0], lv[1], lv[2], &lambda, ray_tri_uv, KNIFE_FLT_EPS)) { + v1, raydir, UNPACK3(tri_cos), &lambda, ray_tri_uv, KNIFE_FLT_EPS)) { /* Check if line coplanar with tri. */ - normal_tri_v3(tri_norm, lv[0], lv[1], lv[2]); - plane_from_point_normal_v3(tri_plane, lv[0], tri_norm); + normal_tri_v3(tri_norm, UNPACK3(tri_cos)); + plane_from_point_normal_v3(tri_plane, tri_cos[0], tri_norm); if ((dist_squared_to_plane_v3(v1, tri_plane) < KNIFE_FLT_EPS) && (dist_squared_to_plane_v3(v2, tri_plane) < KNIFE_FLT_EPS)) { return false; } - interp_v3_v3v3v3_uv(hit_cageco, lv[0], lv[1], lv[2], ray_tri_uv); + interp_v3_v3v3v3_uv(hit_cageco, UNPACK3(tri_cos), ray_tri_uv); /* Now check that far enough away from verts and edges. */ list = knife_get_face_kedges(kcd, ob, base_index, f); for (ref = list->first; ref; ref = ref->next) { @@ -5028,17 +5026,19 @@ void EDBM_mesh_knife(ViewContext *vc, LinkNode *polys, bool use_tag, bool cut_th /* Tag all faces linked to cut edges. */ BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { /* Check are we tagged?, then we are an original face. */ - if (BM_elem_flag_test(e, BM_ELEM_TAG) == false) { - BMFace *f; - BMIter fiter; - BM_ITER_ELEM (f, &fiter, e, BM_FACES_OF_EDGE) { - float cent[3], cent_ss[2]; - BM_face_calc_point_in_face(f, cent); - mul_m4_v3(ob->obmat, cent); - knife_project_v2(kcd, cent, cent_ss); - if (edbm_mesh_knife_point_isect(polys, cent_ss)) { - BM_elem_flag_enable(f, BM_ELEM_TAG); - } + if (BM_elem_flag_test(e, BM_ELEM_TAG)) { + continue; + } + + BMFace *f; + BMIter fiter; + BM_ITER_ELEM (f, &fiter, e, BM_FACES_OF_EDGE) { + float cent[3], cent_ss[2]; + BM_face_calc_point_in_face(f, cent); + mul_m4_v3(ob->obmat, cent); + knife_project_v2(kcd, cent, cent_ss); + if (edbm_mesh_knife_point_isect(polys, cent_ss)) { + BM_elem_flag_enable(f, BM_ELEM_TAG); } } } @@ -5048,43 +5048,45 @@ void EDBM_mesh_knife(ViewContext *vc, LinkNode *polys, bool use_tag, bool cut_th BMFace *f; keep_search = false; BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { - if (BM_elem_flag_test(f, BM_ELEM_TAG) == false && (F_ISECT_IS_UNKNOWN(f))) { - /* Am I connected to a tagged face via an un-tagged edge - * (ie, not across a cut)? */ - BMLoop *l_first = BM_FACE_FIRST_LOOP(f); - BMLoop *l_iter = l_first; - bool found = false; - - do { - if (BM_elem_flag_test(l_iter->e, BM_ELEM_TAG) != false) { - /* Now check if the adjacent faces is tagged. */ - BMLoop *l_radial_iter = l_iter->radial_next; - if (l_radial_iter != l_iter) { - do { - if (BM_elem_flag_test(l_radial_iter->f, BM_ELEM_TAG)) { - found = true; - } - } while ((l_radial_iter = l_radial_iter->radial_next) != l_iter && - (found == false)); - } - } - } while ((l_iter = l_iter->next) != l_first && (found == false)); - - if (found) { - float cent[3], cent_ss[2]; - BM_face_calc_point_in_face(f, cent); - mul_m4_v3(ob->obmat, cent); - knife_project_v2(kcd, cent, cent_ss); - if ((kcd->cut_through || point_is_visible(kcd, cent, cent_ss, (BMElem *)f)) && - edbm_mesh_knife_point_isect(polys, cent_ss)) { - BM_elem_flag_enable(f, BM_ELEM_TAG); - keep_search = true; - } - else { - /* Don't lose time on this face again, set it as outside. */ - F_ISECT_SET_OUTSIDE(f); + if (BM_elem_flag_test(f, BM_ELEM_TAG) || !F_ISECT_IS_UNKNOWN(f)) { + continue; + } + + /* Am I connected to a tagged face via an un-tagged edge + * (ie, not across a cut)? */ + BMLoop *l_first = BM_FACE_FIRST_LOOP(f); + BMLoop *l_iter = l_first; + bool found = false; + + do { + if (BM_elem_flag_test(l_iter->e, BM_ELEM_TAG) != false) { + /* Now check if the adjacent faces is tagged. */ + BMLoop *l_radial_iter = l_iter->radial_next; + if (l_radial_iter != l_iter) { + do { + if (BM_elem_flag_test(l_radial_iter->f, BM_ELEM_TAG)) { + found = true; + } + } while ((l_radial_iter = l_radial_iter->radial_next) != l_iter && + (found == false)); } } + } while ((l_iter = l_iter->next) != l_first && (found == false)); + + if (found) { + float cent[3], cent_ss[2]; + BM_face_calc_point_in_face(f, cent); + mul_m4_v3(ob->obmat, cent); + knife_project_v2(kcd, cent, cent_ss); + if ((kcd->cut_through || point_is_visible(kcd, cent, cent_ss, (BMElem *)f)) && + edbm_mesh_knife_point_isect(polys, cent_ss)) { + BM_elem_flag_enable(f, BM_ELEM_TAG); + keep_search = true; + } + else { + /* Don't lose time on this face again, set it as outside. */ + F_ISECT_SET_OUTSIDE(f); + } } } } while (keep_search); |