diff options
Diffstat (limited to 'source/blender/editors/mesh/loopcut.c')
-rw-r--r-- | source/blender/editors/mesh/loopcut.c | 375 |
1 files changed, 176 insertions, 199 deletions
diff --git a/source/blender/editors/mesh/loopcut.c b/source/blender/editors/mesh/loopcut.c index 42728eb7ea1..313ebb310de 100644 --- a/source/blender/editors/mesh/loopcut.c +++ b/source/blender/editors/mesh/loopcut.c @@ -13,7 +13,7 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * The Original Code is Copyright (C) 2007 Blender Foundation. * All rights reserved. @@ -30,6 +30,8 @@ #include <float.h> +#define _USE_MATH_DEFINES +#include <math.h> #include <string.h> #include <ctype.h> #include <stdio.h> @@ -39,7 +41,6 @@ #include "DNA_screen_types.h" #include "DNA_scene_types.h" #include "DNA_userdef_types.h" -#include "DNA_windowmanager_types.h" #include "MEM_guardedalloc.h" @@ -48,7 +49,7 @@ #include "BLI_blenlib.h" #include "BLI_dynstr.h" /*for WM_operator_pystring */ #include "BLI_editVert.h" -#include "BLI_math.h" +#include "BLI_array.h" #include "BLI_utildefines.h" #include "BKE_blender.h" @@ -59,6 +60,8 @@ #include "BKE_report.h" #include "BKE_scene.h" #include "BKE_array_mallocn.h" +#include "BKE_tessmesh.h" +#include "BKE_depsgraph.h" #include "BIF_gl.h" #include "BIF_glutil.h" /* for paint cursor */ @@ -94,8 +97,8 @@ typedef struct tringselOpData { ViewContext vc; Object *ob; - EditMesh *em; - EditEdge *eed; + BMEditMesh *em; + BMEdge *eed; NumInput num; int extend; @@ -130,17 +133,62 @@ static void ringsel_draw(const bContext *C, ARegion *UNUSED(ar), void *arg) } } +/*given two opposite edges in a face, finds the ordering of their vertices so + that cut preview lines won't cross each other*/ +static void edgering_find_order(BMEditMesh *em, BMEdge *lasteed, BMEdge *eed, + BMVert *lastv1, BMVert *v[2][2]) +{ + BMIter liter; + BMLoop *l, *l2; + int rev; + + l = eed->l; + + /*find correct order for v[1]*/ + if (!(BM_Edge_In_Face(l->f, eed) && BM_Edge_In_Face(l->f, lasteed))) { + BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_LOOP, l) { + if (BM_Edge_In_Face(l->f, eed) && BM_Edge_In_Face(l->f, lasteed)) + break; + } + } + + /*this should never happen*/ + if (!l) { + v[0][0] = eed->v1; + v[0][1] = eed->v2; + v[1][0] = lasteed->v1; + v[1][1] = lasteed->v2; + return; + } + + l2 = BM_OtherFaceLoop(l->e, l->f, eed->v1); + rev = (l2 == l->prev); + while (l2->v != lasteed->v1 && l2->v != lasteed->v2) { + l2 = rev ? l2->prev : l2->next; + } + + if (l2->v == lastv1) { + v[0][0] = eed->v1; + v[0][1] = eed->v2; + } else { + v[0][0] = eed->v2; + v[0][1] = eed->v1; + } +} + static void edgering_sel(tringselOpData *lcd, int previewlines, int select) { - EditMesh *em = lcd->em; - EditEdge *startedge = lcd->eed; - EditEdge *eed; - EditFace *efa; - EditVert *v[2][2]; + BMEditMesh *em = lcd->em; + BMEdge *startedge = lcd->eed; + BMEdge *eed, *lasteed; + BMVert *v[2][2], *lastv1; + BMWalker walker; float (*edges)[2][3] = NULL; - V_DYNDECLARE(edges); + BLI_array_declare(edges); float co[2][3]; - int looking=1, i, tot=0; + int i, tot=0; + + memset(v, 0, sizeof(v)); if (!startedge) return; @@ -152,110 +200,81 @@ static void edgering_sel(tringselOpData *lcd, int previewlines, int select) } if (!lcd->extend) { - EM_clear_flag_all(lcd->em, SELECT); + EDBM_clear_flag_all(lcd->em, BM_SELECT); } - /* in eed->f1 we put the valence (amount of faces in edge) */ - /* in eed->f2 we put tagged flag as correct loop */ - /* in efa->f1 we put tagged flag as correct to select */ + if (select) { + BMW_Init(&walker, em->bm, BMW_EDGERING, 0,0,0,0, BMW_NIL_LAY); + eed = BMW_Begin(&walker, startedge); + for (; eed; eed=BMW_Step(&walker)) { + BM_Select(em->bm, eed, 1); + } + BMW_End(&walker); - for(eed= em->edges.first; eed; eed= eed->next) { - eed->f1= 0; - eed->f2= 0; + return; } - for(efa= em->faces.first; efa; efa= efa->next) { - efa->f1= 0; - if(efa->h==0) { - efa->e1->f1++; - efa->e2->f1++; - efa->e3->f1++; - if(efa->e4) efa->e4->f1++; - } - } - - // tag startedge OK - startedge->f2= 1; - - while(looking) { - looking= 0; - - for(efa= em->faces.first; efa; efa= efa->next) { - if(efa->e4 && efa->f1==0 && efa->h == 0) { // not done quad - if(efa->e1->f1<=2 && efa->e2->f1<=2 && efa->e3->f1<=2 && efa->e4->f1<=2) { // valence ok - - // if edge tagged, select opposing edge and mark face ok - if(efa->e1->f2) { - efa->e3->f2= 1; - efa->f1= 1; - looking= 1; - } - else if(efa->e2->f2) { - efa->e4->f2= 1; - efa->f1= 1; - looking= 1; - } - if(efa->e3->f2) { - efa->e1->f2= 1; - efa->f1= 1; - looking= 1; - } - if(efa->e4->f2) { - efa->e2->f2= 1; - efa->f1= 1; - looking= 1; - } - } + BMW_Init(&walker, em->bm, BMW_EDGERING, 0,0,0,0, BMW_NIL_LAY); + eed = startedge = BMW_Begin(&walker, startedge); + lastv1 = NULL; + for (lasteed=NULL; eed; eed=BMW_Step(&walker)) { + if (lasteed) { + if (lastv1) { + v[1][0] = v[0][0]; + v[1][1] = v[0][1]; + } else { + v[1][0] = lasteed->v1; + v[1][1] = lasteed->v2; + lastv1 = lasteed->v1; + } + + edgering_find_order(em, lasteed, eed, lastv1, v); + lastv1 = v[0][0]; + + for(i=1;i<=previewlines;i++){ + co[0][0] = (v[0][1]->co[0] - v[0][0]->co[0])*(i/((float)previewlines+1))+v[0][0]->co[0]; + co[0][1] = (v[0][1]->co[1] - v[0][0]->co[1])*(i/((float)previewlines+1))+v[0][0]->co[1]; + co[0][2] = (v[0][1]->co[2] - v[0][0]->co[2])*(i/((float)previewlines+1))+v[0][0]->co[2]; + + co[1][0] = (v[1][1]->co[0] - v[1][0]->co[0])*(i/((float)previewlines+1))+v[1][0]->co[0]; + co[1][1] = (v[1][1]->co[1] - v[1][0]->co[1])*(i/((float)previewlines+1))+v[1][0]->co[1]; + co[1][2] = (v[1][1]->co[2] - v[1][0]->co[2])*(i/((float)previewlines+1))+v[1][0]->co[2]; + + BLI_array_growone(edges); + VECCOPY(edges[tot][0], co[0]); + VECCOPY(edges[tot][1], co[1]); + tot++; } } + lasteed = eed; } - if(previewlines > 0 && !select){ - for(efa= em->faces.first; efa; efa= efa->next) { - if(efa->v4 == NULL) { continue; } - if(efa->h == 0){ - if(efa->e1->f2 == 1){ - if(efa->e1->h == 1 || efa->e3->h == 1 ) - continue; - - v[0][0] = efa->v1; - v[0][1] = efa->v2; - v[1][0] = efa->v4; - v[1][1] = efa->v3; - } else if(efa->e2->f2 == 1){ - if(efa->e2->h == 1 || efa->e4->h == 1) - continue; - v[0][0] = efa->v2; - v[0][1] = efa->v3; - v[1][0] = efa->v1; - v[1][1] = efa->v4; - } else { continue; } - - for(i=1;i<=previewlines;i++){ - co[0][0] = (v[0][1]->co[0] - v[0][0]->co[0])*(i/((float)previewlines+1))+v[0][0]->co[0]; - co[0][1] = (v[0][1]->co[1] - v[0][0]->co[1])*(i/((float)previewlines+1))+v[0][0]->co[1]; - co[0][2] = (v[0][1]->co[2] - v[0][0]->co[2])*(i/((float)previewlines+1))+v[0][0]->co[2]; - - co[1][0] = (v[1][1]->co[0] - v[1][0]->co[0])*(i/((float)previewlines+1))+v[1][0]->co[0]; - co[1][1] = (v[1][1]->co[1] - v[1][0]->co[1])*(i/((float)previewlines+1))+v[1][0]->co[1]; - co[1][2] = (v[1][1]->co[2] - v[1][0]->co[2])*(i/((float)previewlines+1))+v[1][0]->co[2]; - - V_GROW(edges); - VECCOPY(edges[tot][0], co[0]); - VECCOPY(edges[tot][1], co[1]); - tot++; - } - } - } - } else { - select = (startedge->f & SELECT) == 0; + if (lasteed != startedge && BM_Edge_Share_Faces(lasteed, startedge)) { + v[1][0] = v[0][0]; + v[1][1] = v[0][1]; + + edgering_find_order(em, lasteed, startedge, lastv1, v); + + for(i=1;i<=previewlines;i++){ + if (!v[0][0] || !v[0][1] || !v[1][0] || !v[1][1]) + continue; + + co[0][0] = (v[0][1]->co[0] - v[0][0]->co[0])*(i/((float)previewlines+1))+v[0][0]->co[0]; + co[0][1] = (v[0][1]->co[1] - v[0][0]->co[1])*(i/((float)previewlines+1))+v[0][0]->co[1]; + co[0][2] = (v[0][1]->co[2] - v[0][0]->co[2])*(i/((float)previewlines+1))+v[0][0]->co[2]; - /* select the edges */ - for(eed= em->edges.first; eed; eed= eed->next) { - if(eed->f2) EM_select_edge(eed, select); + co[1][0] = (v[1][1]->co[0] - v[1][0]->co[0])*(i/((float)previewlines+1))+v[1][0]->co[0]; + co[1][1] = (v[1][1]->co[1] - v[1][0]->co[1])*(i/((float)previewlines+1))+v[1][0]->co[1]; + co[1][2] = (v[1][1]->co[2] - v[1][0]->co[2])*(i/((float)previewlines+1))+v[1][0]->co[2]; + + BLI_array_growone(edges); + VECCOPY(edges[tot][0], co[0]); + VECCOPY(edges[tot][1], co[1]); + tot++; } } + BMW_End(&walker); lcd->edges = edges; lcd->totedge = tot; } @@ -265,7 +284,8 @@ static void ringsel_find_edge(tringselOpData *lcd, int cuts) if (lcd->eed) { edgering_sel(lcd, cuts, 0); } else if(lcd->edges) { - MEM_freeN(lcd->edges); + if (lcd->edges) + MEM_freeN(lcd->edges); lcd->edges = NULL; lcd->totedge = 0; } @@ -274,17 +294,18 @@ static void ringsel_find_edge(tringselOpData *lcd, int cuts) static void ringsel_finish(bContext *C, wmOperator *op) { tringselOpData *lcd= op->customdata; - int cuts= (lcd->do_cut)? RNA_int_get(op->ptr,"number_cuts"): 0; + int cuts= RNA_int_get(op->ptr, "number_cuts"); if (lcd->eed) { - EditMesh *em = BKE_mesh_get_editmesh(lcd->ob->data); - + BMEditMesh *em = lcd->em; + edgering_sel(lcd, cuts, 1); if (lcd->do_cut) { - - esubdivideflag(lcd->ob, em, SELECT, 0.0f, 0.0f, 0, cuts, 0, SUBDIV_SELECT_LOOPCUT); - + BM_esubdivideflag(lcd->ob, em->bm, BM_SELECT, 0.0f, + 0.0f, 0, cuts, SUBDIV_SELECT_LOOPCUT, + SUBD_PATH, 0, 0, 0); + /* force edge slide to edge select mode in in face select mode */ if (em->selectmode & SCE_SELECT_FACE) { if (em->selectmode == SCE_SELECT_FACE) @@ -292,33 +313,35 @@ static void ringsel_finish(bContext *C, wmOperator *op) else em->selectmode &= ~SCE_SELECT_FACE; CTX_data_tool_settings(C)->selectmode= em->selectmode; - EM_selectmode_set(em); + EDBM_selectmode_set(em); + + WM_event_add_notifier(C, NC_SCENE|ND_TOOLSETTINGS, CTX_data_scene(C)); WM_event_add_notifier(C, NC_SCENE|ND_TOOLSETTINGS, CTX_data_scene(C)); } - + + WM_event_add_notifier(C, NC_GEOM|ND_SELECT|ND_DATA, lcd->ob->data); DAG_id_tag_update(lcd->ob->data, 0); - WM_event_add_notifier(C, NC_GEOM|ND_DATA, lcd->ob->data); } else { /* sets as active, useful for other tools */ if(em->selectmode & SCE_SELECT_VERTEX) - EM_store_selection(em, lcd->eed->v1, EDITVERT); + EDBM_selectmode_flush(em); if(em->selectmode & SCE_SELECT_EDGE) - EM_store_selection(em, lcd->eed, EDITEDGE); + EDBM_selectmode_flush(em); - EM_selectmode_flush(lcd->em); + EDBM_selectmode_flush(lcd->em); WM_event_add_notifier(C, NC_GEOM|ND_SELECT, lcd->ob->data); } } } /* called when modal loop selection is done... */ -static void ringsel_exit(wmOperator *op) +static void ringsel_exit(bContext *UNUSED(C), wmOperator *op) { tringselOpData *lcd= op->customdata; - + /* deactivate the extra drawing stuff in 3D-View */ ED_region_draw_cb_exit(lcd->ar->type, lcd->draw_handle); @@ -344,7 +367,7 @@ static int ringsel_init (bContext *C, wmOperator *op, int do_cut) lcd->ar= CTX_wm_region(C); lcd->draw_handle= ED_region_draw_cb_activate(lcd->ar->type, ringsel_draw, lcd, REGION_DRAW_POST_VIEW); lcd->ob = CTX_data_edit_object(C); - lcd->em= BKE_mesh_get_editmesh((Mesh *)lcd->ob->data); + lcd->em= ((Mesh *)lcd->ob->data)->edit_btmesh; lcd->extend = do_cut ? 0 : RNA_boolean_get(op->ptr, "extend"); lcd->do_cut = do_cut; @@ -359,55 +382,18 @@ static int ringsel_init (bContext *C, wmOperator *op, int do_cut) return 1; } -static int ringcut_cancel (bContext *UNUSED(C), wmOperator *op) +static int ringcut_cancel (bContext *C, wmOperator *op) { /* this is just a wrapper around exit() */ - ringsel_exit(op); + ringsel_exit(C, op); return OPERATOR_CANCELLED; } -static int ringsel_invoke (bContext *C, wmOperator *op, wmEvent *evt) -{ - tringselOpData *lcd; - EditEdge *edge; - int dist = 75; - - view3d_operator_needs_opengl(C); - - if (!ringsel_init(C, op, 0)) - return OPERATOR_CANCELLED; - - lcd = op->customdata; - - if (lcd->em->selectmode == SCE_SELECT_FACE) { - ringsel_exit(op); - WM_operator_name_call(C, "MESH_OT_loop_select", WM_OP_INVOKE_REGION_WIN, NULL); - return OPERATOR_CANCELLED; - } - - lcd->vc.mval[0] = evt->mval[0]; - lcd->vc.mval[1] = evt->mval[1]; - - edge = findnearestedge(&lcd->vc, &dist); - if(!edge) { - ringsel_exit(op); - return OPERATOR_CANCELLED; - } - - lcd->eed = edge; - ringsel_find_edge(lcd, 1); - - ringsel_finish(C, op); - ringsel_exit(op); - - return OPERATOR_FINISHED; -} - static int ringcut_invoke (bContext *C, wmOperator *op, wmEvent *evt) { Object *obedit= CTX_data_edit_object(C); tringselOpData *lcd; - EditEdge *edge; + BMEdge *edge; int dist = 75; if(modifiers_isDeformedByLattice(obedit) || modifiers_isDeformedByArmature(obedit)) @@ -425,7 +411,7 @@ static int ringcut_invoke (bContext *C, wmOperator *op, wmEvent *evt) lcd->vc.mval[0] = evt->mval[0]; lcd->vc.mval[1] = evt->mval[1]; - edge = findnearestedge(&lcd->vc, &dist); + edge = EDBM_findnearestedge(&lcd->vc, &dist); if (edge != lcd->eed) { lcd->eed = edge; ringsel_find_edge(lcd, 1); @@ -435,22 +421,23 @@ static int ringcut_invoke (bContext *C, wmOperator *op, wmEvent *evt) return OPERATOR_RUNNING_MODAL; } -static int ringcut_modal (bContext *C, wmOperator *op, wmEvent *event) +static int loopcut_modal (bContext *C, wmOperator *op, wmEvent *event) { int cuts= RNA_int_get(op->ptr,"number_cuts"); tringselOpData *lcd= op->customdata; view3d_operator_needs_opengl(C); - switch (event->type) { + case RETKEY: case LEFTMOUSE: /* confirm */ // XXX hardcoded if (event->val == KM_PRESS) { /* finish */ ED_region_tag_redraw(lcd->ar); ringsel_finish(C, op); - ringsel_exit(op); + ringsel_exit(C, op); + ED_area_headerprint(CTX_wm_area(C), NULL); return OPERATOR_FINISHED; @@ -459,6 +446,11 @@ static int ringcut_modal (bContext *C, wmOperator *op, wmEvent *event) ED_region_tag_redraw(lcd->ar); break; case RIGHTMOUSE: /* abort */ // XXX hardcoded + ED_region_tag_redraw(lcd->ar); + ringsel_exit(C, op); + ED_area_headerprint(CTX_wm_area(C), NULL); + + return OPERATOR_FINISHED; case ESCKEY: if (event->val == KM_RELEASE) { /* cancel */ @@ -470,35 +462,37 @@ static int ringcut_modal (bContext *C, wmOperator *op, wmEvent *event) ED_region_tag_redraw(lcd->ar); break; - case WHEELUPMOUSE: /* change number of cuts */ case PADPLUSKEY: case PAGEUPKEY: - if (event->val == KM_PRESS) { - cuts++; - RNA_int_set(op->ptr, "number_cuts",cuts); - ringsel_find_edge(lcd, cuts); - - ED_region_tag_redraw(lcd->ar); - } + case WHEELUPMOUSE: /* change number of cuts */ + if (event->val == KM_RELEASE) + break; + + cuts++; + RNA_int_set(op->ptr,"number_cuts",cuts); + ringsel_find_edge(lcd, cuts); + + ED_region_tag_redraw(lcd->ar); break; - case WHEELDOWNMOUSE: /* change number of cuts */ case PADMINUS: case PAGEDOWNKEY: - if (event->val == KM_PRESS) { - cuts=MAX2(cuts-1,1); - RNA_int_set(op->ptr,"number_cuts",cuts); - ringsel_find_edge(lcd, cuts); - - ED_region_tag_redraw(lcd->ar); - } + case WHEELDOWNMOUSE: /* change number of cuts */ + if (event->val == KM_RELEASE) + break; + + cuts=MAX2(cuts-1,1); + RNA_int_set(op->ptr,"number_cuts",cuts); + ringsel_find_edge(lcd, cuts); + + ED_region_tag_redraw(lcd->ar); break; case MOUSEMOVE: { /* mouse moved somewhere to select another loop */ int dist = 75; - EditEdge *edge; + BMEdge *edge; lcd->vc.mval[0] = event->mval[0]; lcd->vc.mval[1] = event->mval[1]; - edge = findnearestedge(&lcd->vc, &dist); + edge = EDBM_findnearestedge(&lcd->vc, &dist); if (edge != lcd->eed) { lcd->eed = edge; @@ -531,23 +525,6 @@ static int ringcut_modal (bContext *C, wmOperator *op, wmEvent *event) return OPERATOR_RUNNING_MODAL; } -void MESH_OT_edgering_select (wmOperatorType *ot) -{ - /* description */ - ot->name= "Edge Ring Select"; - ot->idname= "MESH_OT_edgering_select"; - ot->description= "Select an edge ring"; - - /* callbacks */ - ot->invoke= ringsel_invoke; - ot->poll= ED_operator_editmesh_region_view3d; - - /* flags */ - ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO; - - RNA_def_boolean(ot->srna, "extend", 0, "Extend", "Extend the selection"); -} - void MESH_OT_loopcut (wmOperatorType *ot) { /* description */ @@ -557,7 +534,7 @@ void MESH_OT_loopcut (wmOperatorType *ot) /* callbacks */ ot->invoke= ringcut_invoke; - ot->modal= ringcut_modal; + ot->modal= loopcut_modal; ot->cancel= ringcut_cancel; ot->poll= ED_operator_editmesh_region_view3d; |