diff options
Diffstat (limited to 'source/blender/editors/mesh/editmesh_tools.c')
-rw-r--r-- | source/blender/editors/mesh/editmesh_tools.c | 218 |
1 files changed, 101 insertions, 117 deletions
diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index 891e1487781..a76d09827f0 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -153,22 +153,19 @@ void MESH_OT_subdivide(wmOperatorType *ot) } -void EMBM_project_snap_verts(bContext *C, ARegion *ar, BMEditMesh *em) +void EMBM_project_snap_verts(bContext *C, ARegion *ar, Object *obedit, BMEditMesh *em) { - Object *obedit = em->ob; BMIter iter; BMVert *eve; - ED_view3d_init_mats_rv3d(obedit, ar->regiondata); - BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) { - float mval[2], co_proj[3], no_dummy[3]; + float mval[2], vec[3], no_dummy[3]; int dist_dummy; - if (ED_view3d_project_float_object(ar, eve->co, mval, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) { - if (snapObjectsContext(C, mval, &dist_dummy, co_proj, no_dummy, SNAP_NOT_OBEDIT)) { - mul_v3_m4v3(eve->co, obedit->imat, co_proj); - } + mul_v3_m4v3(vec, obedit->obmat, eve->co); + ED_view3d_project_float_noclip(ar, vec, mval); + if (snapObjectsContext(C, mval, &dist_dummy, vec, no_dummy, SNAP_NOT_OBEDIT)) { + mul_v3_m4v3(eve->co, obedit->imat, vec); } } } @@ -442,17 +439,16 @@ static int edbm_extrude_mesh(Scene *scene, Object *obedit, BMEditMesh *em, wmOpe zero_v3(nor); - /* XXX If those popup menus were to be enabled again, please get rid of this "menu string" syntax! */ if (em->selectmode & SCE_SELECT_VERTEX) { if (em->bm->totvertsel == 0) nr = 0; else if (em->bm->totvertsel == 1) nr = 4; else if (em->bm->totedgesel == 0) nr = 4; else if (em->bm->totfacesel == 0) - nr = 3; /* pupmenu("Extrude %t|Only Edges %x3|Only Vertices %x4"); */ + nr = 3; // pupmenu("Extrude %t|Only Edges%x3|Only Vertices%x4"); else if (em->bm->totfacesel == 1) - nr = 1; /* pupmenu("Extrude %t|Region %x1|Only Edges% x3|Only Vertices %x4"); */ + nr = 1; // pupmenu("Extrude %t|Region %x1|Only Edges%x3|Only Vertices%x4"); else - nr = 1; /* pupmenu("Extrude %t|Region %x1|Individual Faces %x2|Only Edges %x3|Only Vertices %x4"); */ + nr = 1; // pupmenu("Extrude %t|Region %x1||Individual Faces %x2|Only Edges%x3|Only Vertices%x4"); } else if (em->selectmode & SCE_SELECT_EDGE) { if (em->bm->totedgesel == 0) nr = 0; @@ -462,16 +458,16 @@ static int edbm_extrude_mesh(Scene *scene, Object *obedit, BMEditMesh *em, wmOpe else if (em->totedgesel == 1) nr = 3; else if (em->totfacesel == 0) nr = 3; else if (em->totfacesel == 1) - nr = 1; /* pupmenu("Extrude %t|Region %x1|Only Edges %x3"); */ + nr = 1; // pupmenu("Extrude %t|Region %x1|Only Edges%x3"); else - nr = 1; /* pupmenu("Extrude %t|Region %x1|Individual Faces %x2|Only Edges %x3"); */ + nr = 1; // pupmenu("Extrude %t|Region %x1||Individual Faces %x2|Only Edges%x3"); #endif } else { if (em->bm->totfacesel == 0) nr = 0; else if (em->bm->totfacesel == 1) nr = 1; else - nr = 1; /* pupmenu("Extrude %t|Region %x1|Individual Faces %x2"); */ + nr = 1; // pupmenu("Extrude %t|Region %x1||Individual Faces %x2"); } if (nr < 1) return 'g'; @@ -734,10 +730,7 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, wmEvent short use_proj; em_setup_viewcontext(C, &vc); - - ED_view3d_init_mats_rv3d(vc.obedit, vc.rv3d); - - + use_proj = ((vc.scene->toolsettings->snap_flag & SCE_SNAP) && (vc.scene->toolsettings->snap_mode == SCE_SNAP_MODE_FACE)); @@ -765,27 +758,27 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, wmEvent done = FALSE; BM_ITER_MESH (eed, &iter, vc.em->bm, BM_EDGES_OF_MESH) { if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) { - float co1[2], co2[2]; - - if ((ED_view3d_project_float_object(vc.ar, eed->v1->co, co1, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) && - (ED_view3d_project_float_object(vc.ar, eed->v2->co, co2, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK)) - { - /* 2D rotate by 90d while adding. - * (x, y) = (y, -x) - * - * accumulate the screenspace normal in 2D, - * with screenspace edge length weighting the result. */ - if (line_point_side_v2(co1, co2, mval_f) >= 0.0f) { - nor[0] += (co1[1] - co2[1]); - nor[1] += -(co1[0] - co2[0]); - } - else { - nor[0] += (co2[1] - co1[1]); - nor[1] += -(co2[0] - co1[0]); - } - done = TRUE; + float co1[3], co2[3]; + mul_v3_m4v3(co1, vc.obedit->obmat, eed->v1->co); + mul_v3_m4v3(co2, vc.obedit->obmat, eed->v2->co); + ED_view3d_project_float_noclip(vc.ar, co1, co1); + ED_view3d_project_float_noclip(vc.ar, co2, co2); + + /* 2D rotate by 90d while adding. + * (x, y) = (y, -x) + * + * accumulate the screenspace normal in 2D, + * with screenspace edge length weighting the result. */ + if (line_point_side_v2(co1, co2, mval_f) >= 0.0f) { + nor[0] += (co1[1] - co2[1]); + nor[1] += -(co1[0] - co2[0]); + } + else { + nor[0] += (co2[1] - co1[1]); + nor[1] += -(co2[0] - co1[0]); } } + done = TRUE; } if (done) { @@ -842,7 +835,7 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, wmEvent /* also project the source, for retopo workflow */ if (use_proj) - EMBM_project_snap_verts(C, vc.ar, vc.em); + EMBM_project_snap_verts(C, vc.ar, vc.obedit, vc.em); } edbm_extrude_edge(vc.obedit, vc.em, BM_ELEM_SELECT, nor); @@ -875,7 +868,7 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, wmEvent } if (use_proj) - EMBM_project_snap_verts(C, vc.ar, vc.em); + EMBM_project_snap_verts(C, vc.ar, vc.obedit, vc.em); /* This normally happens when pushing undo but modal operators * like this one don't push undo data until after modal mode is @@ -2147,7 +2140,7 @@ static int edbm_select_vertex_path_exec(bContext *C, wmOperator *op) } /* if those are not found, because vertices where selected by e.g. - * border or circle select, find two selected vertices */ + border or circle select, find two selected vertices */ if (svert == NULL) { BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { if (!BM_elem_flag_test(eve, BM_ELEM_SELECT) || BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) @@ -2157,7 +2150,7 @@ static int edbm_select_vertex_path_exec(bContext *C, wmOperator *op) else if (evert == NULL) evert = eve; else { /* more than two vertices are selected, - * show warning message and cancel operator */ + show warning message and cancel operator */ svert = evert = NULL; break; } @@ -2533,6 +2526,11 @@ void MESH_OT_solidify(wmOperatorType *ot) RNA_def_property_ui_range(prop, -10, 10, 0.1, 4); } +typedef struct CutCurve { + float x; + float y; +} CutCurve; + /* ******************************************************************** */ /* Knife Subdivide Tool. Subdivides edges intersected by a mouse trail * drawn by user. @@ -2566,14 +2564,15 @@ static EnumPropertyItem knife_items[] = { /* bm_edge_seg_isect() Determines if and where a mouse trail intersects an BMEdge */ -static float bm_edge_seg_isect(const float sco_a[2], const float sco_b[2], - float (*mouse_path)[2], int len, char mode, int *isected) +static float bm_edge_seg_isect(BMEdge *e, CutCurve *c, int len, char mode, + struct GHash *gh, int *isected) { #define MAXSLOPE 100000 float x11, y11, x12 = 0, y12 = 0, x2max, x2min, y2max; float y2min, dist, lastdist = 0, xdiff2, xdiff1; float m1, b1, m2, b2, x21, x22, y21, y22, xi; float yi, x1min, x1max, y1max, y1min, perc = 0; + float *scr; float threshold = 0.0; int i; @@ -2581,11 +2580,13 @@ static float bm_edge_seg_isect(const float sco_a[2], const float sco_b[2], // XXX threshold = scene->toolsettings->select_thresh / 100; /* Get screen coords of verts */ - x21 = sco_a[0]; - y21 = sco_a[1]; + scr = BLI_ghash_lookup(gh, e->v1); + x21 = scr[0]; + y21 = scr[1]; - x22 = sco_b[0]; - y22 = sco_b[1]; + scr = BLI_ghash_lookup(gh, e->v2); + x22 = scr[0]; + y22 = scr[1]; xdiff2 = (x22 - x21); if (xdiff2) { @@ -2607,11 +2608,11 @@ static float bm_edge_seg_isect(const float sco_a[2], const float sco_b[2], y11 = y12; } else { - x11 = mouse_path[i][0]; - y11 = mouse_path[i][1]; + x11 = c[i].x; + y11 = c[i].y; } - x12 = mouse_path[i][0]; - y12 = mouse_path[i][1]; + x12 = c[i].x; + y12 = c[i].y; /* test e->v1 */ if ((x11 == x21 && y11 == y21) || (x12 == x21 && y12 == y21)) { @@ -2635,11 +2636,11 @@ static float bm_edge_seg_isect(const float sco_a[2], const float sco_b[2], y11 = y12; } else { - x11 = mouse_path[i][0]; - y11 = mouse_path[i][1]; + x11 = c[i].x; + y11 = c[i].y; } - x12 = mouse_path[i][0]; - y12 = mouse_path[i][1]; + x12 = c[i].x; + y12 = c[i].y; /* Perp. Distance from point to line */ if (m2 != MAXSLOPE) dist = (y12 - m2 * x12 - b2); /* /sqrt(m2 * m2 + 1); Only looking for */ @@ -2717,9 +2718,9 @@ static float bm_edge_seg_isect(const float sco_a[2], const float sco_b[2], lastdist = dist; } return perc; -} +} -#define ELE_EDGE_CUT 1 +#define MAX_CUTS 2048 static int edbm_knife_cut_exec(bContext *C, wmOperator *op) { @@ -2731,93 +2732,76 @@ static int edbm_knife_cut_exec(bContext *C, wmOperator *op) BMIter iter; BMEdge *be; BMOperator bmop; + CutCurve curve[MAX_CUTS]; + struct GHash *gh; float isect = 0.0f; - int len = 0, isected, i; + float *scr, co[4]; + int len = 0, isected; short numcuts = 1, mode = RNA_int_get(op->ptr, "type"); - - /* allocd vars */ - float (*screen_vert_coords)[2], (*sco)[2], (*mouse_path)[2]; /* edit-object needed for matrix, and ar->regiondata for projections to work */ if (ELEM3(NULL, obedit, ar, ar->regiondata)) return OPERATOR_CANCELLED; if (bm->totvertsel < 2) { - BKE_report(op->reports, RPT_ERROR, "No edges are selected to operate on"); - return OPERATOR_CANCELLED; - } - - len = RNA_collection_length(op->ptr, "path"); - - if (len < 2) { - BKE_report(op->reports, RPT_ERROR, "Mouse path too short"); + //error("No edges are selected to operate on"); return OPERATOR_CANCELLED; } - mouse_path = MEM_mallocN(len * sizeof(*mouse_path), __func__); - /* get the cut curve */ RNA_BEGIN(op->ptr, itemptr, "path") { - RNA_float_get_array(&itemptr, "loc", (float *)&mouse_path[len]); + RNA_float_get_array(&itemptr, "loc", (float *)&curve[len]); + len++; + if (len >= MAX_CUTS) { + break; + } } RNA_END; - - /* for ED_view3d_project_float_object */ - ED_view3d_init_mats_rv3d(obedit, ar->regiondata); - - /* TODO, investigate using index lookup for screen_vert_coords() rather then a hash table */ + + if (len < 2) { + return OPERATOR_CANCELLED; + } /* the floating point coordinates of verts in screen space will be stored in a hash table according to the vertices pointer */ - screen_vert_coords = sco = MEM_mallocN(bm->totvert * sizeof(float) * 2, __func__); - - BM_ITER_MESH_INDEX (bv, &iter, bm, BM_VERTS_OF_MESH, i) { - if (ED_view3d_project_float_object(ar, bv->co, *sco, V3D_PROJ_TEST_NOP) != V3D_PROJ_RET_OK) { - copy_v2_fl(*sco, FLT_MAX); /* set error value */ - } - BM_elem_index_set(bv, i); /* set_ok */ - sco++; - + gh = BLI_ghash_ptr_new("knife cut exec"); + for (bv = BM_iter_new(&iter, bm, BM_VERTS_OF_MESH, NULL); bv; bv = BM_iter_step(&iter)) { + scr = MEM_mallocN(sizeof(float) * 2, "Vertex Screen Coordinates"); + copy_v3_v3(co, bv->co); + co[3] = 1.0f; + mul_m4_v4(obedit->obmat, co); + ED_view3d_project_float(ar, co, scr); + BLI_ghash_insert(gh, bv, scr); } - bm->elem_index_dirty &= ~BM_VERT; /* clear dirty flag */ if (!EDBM_op_init(em, &bmop, op, "subdivide_edges")) { - MEM_freeN(mouse_path); - MEM_freeN(screen_vert_coords); return OPERATOR_CANCELLED; } /* store percentage of edge cut for KNIFE_EXACT here.*/ for (be = BM_iter_new(&iter, bm, BM_EDGES_OF_MESH, NULL); be; be = BM_iter_step(&iter)) { - int is_cut = FALSE; if (BM_elem_flag_test(be, BM_ELEM_SELECT)) { - const float *sco_a = screen_vert_coords[BM_elem_index_get(be->v1)]; - const float *sco_b = screen_vert_coords[BM_elem_index_get(be->v2)]; - - /* check for error value (vert cant be projected) */ - if ((sco_a[0] != FLT_MAX) && (sco_b[0] != FLT_MAX)) { - isect = bm_edge_seg_isect(sco_a, sco_b, mouse_path, len, mode, &isected); - - if (isect != 0.0f) { - if (mode != KNIFE_MULTICUT && mode != KNIFE_MIDPOINT) { - BMO_slot_map_float_insert(bm, &bmop, - "edgepercents", - be, isect); - } + isect = bm_edge_seg_isect(be, curve, len, mode, gh, &isected); + + if (isect != 0.0f) { + if (mode != KNIFE_MULTICUT && mode != KNIFE_MIDPOINT) { + BMO_slot_map_float_insert(bm, &bmop, + "edgepercents", + be, isect); + } + BMO_elem_flag_enable(bm, be, 1); + } + else { + BMO_elem_flag_disable(bm, be, 1); } } - - BMO_elem_flag_set(bm, be, ELE_EDGE_CUT, is_cut); + else { + BMO_elem_flag_disable(bm, be, 1); + } } - - - /* free all allocs */ - MEM_freeN(screen_vert_coords); - MEM_freeN(mouse_path); - - - BMO_slot_buffer_from_enabled_flag(bm, &bmop, "edges", BM_EDGE, ELE_EDGE_CUT); + + BMO_slot_buffer_from_enabled_flag(bm, &bmop, "edges", BM_EDGE, 1); if (mode == KNIFE_MIDPOINT) numcuts = 1; BMO_slot_int_set(&bmop, "numcuts", numcuts); @@ -2832,14 +2816,14 @@ static int edbm_knife_cut_exec(bContext *C, wmOperator *op) if (!EDBM_op_finish(em, &bmop, op, TRUE)) { return OPERATOR_CANCELLED; } + + BLI_ghash_free(gh, NULL, (GHashValFreeFP)MEM_freeN); EDBM_update_generic(C, em, TRUE); return OPERATOR_FINISHED; } -#undef ELE_EDGE_CUT - void MESH_OT_knife_cut(wmOperatorType *ot) { PropertyRNA *prop; |