svn merge ^/trunk/blender -r42009:42053
[blender.git] / source / blender / editors / mesh / loopcut.c
index 42728eb..a6f71d9 100644 (file)
@@ -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);
+               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);
+       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;