merge with/from trunk at r35190
[blender.git] / source / blender / editors / mesh / knifetool.c
index 89b63183c315e1b8f654d7003e2907be22ef61ec..60910497fad1813cee3d1f85264a6a5c777ec1b8 100755 (executable)
@@ -1,4 +1,3 @@
-#if 1
 /**
  * $Id$
  *
@@ -128,7 +127,8 @@ typedef struct knifetool_opdata {
        ARegion *ar;            /* region that knifetool was activated in */
        void *draw_handle;      /* for drawing preview loop */
        ViewContext vc;
-
+       bContext *C;
+       
        Object *ob;
        BMEditMesh *em;
        
@@ -166,6 +166,7 @@ typedef struct knifetool_opdata {
        BLI_mempool *refs;
        
        float projmat[4][4];
+       int is_ortho, clipsta, clipend;
        
        enum {
                MODE_IDLE,
@@ -176,6 +177,17 @@ typedef struct knifetool_opdata {
 
 static ListBase *knife_get_face_kedges(knifetool_opdata *kcd, BMFace *f);
 
+void knife_project_v3(knifetool_opdata *kcd, float co[3], float sco[3])
+{
+       if (kcd->is_ortho) {
+               mul_v3_m4v3(sco, kcd->projmat, co);
+               
+               sco[0] = (float)(kcd->ar->winx/2.0f)+(kcd->ar->winx/2.0f)*sco[0];
+               sco[1] = (float)(kcd->ar->winy/2.0f)+(kcd->ar->winy/2.0f)*sco[1];
+       } else
+               view3d_project_float(kcd->ar, co, sco, kcd->projmat);
+}
+
 static KnifeEdge *new_knife_edge(knifetool_opdata *kcd)
 {
        kcd->totkedge++;
@@ -191,7 +203,7 @@ static KnifeVert *new_knife_vert(knifetool_opdata *kcd, float *co)
        copy_v3_v3(kfv->co, co);
        copy_v3_v3(kfv->sco, co);
 
-       view3d_project_float(kcd->ar, kfv->co, kfv->sco, kcd->projmat);
+       knife_project_v3(kcd, kfv->co, kfv->sco);
 
        return kfv;
 }
@@ -609,9 +621,9 @@ static void knifetool_draw(const bContext *C, ARegion *ar, void *arg)
                lh = kcd->linehits;
                for (i=0; i<kcd->totlinehit; i++, lh++) {
                        float sv1[3], sv2[3];
-
-                       view3d_project_float_v3(kcd->ar, lh->kfe->v1->co, sv1, kcd->projmat);
-                       view3d_project_float_v3(kcd->ar, lh->kfe->v2->co, sv2, kcd->projmat);
+                       
+                       knife_project_v3(kcd, lh->kfe->v1->co, sv1);
+                       knife_project_v3(kcd, lh->kfe->v2->co, sv2);
                        
                        if (len_v2v2(lh->shit, sv1) < kcd->vthresh/4) {
                                copy_v3_v3(lh->hit, lh->kfe->v1->co);
@@ -683,20 +695,45 @@ static void knifetool_draw(const bContext *C, ARegion *ar, void *arg)
        glEnable(GL_DEPTH_TEST);
 }
 
+void _print_smhash(SmallHash *hash)
+{
+       int i, linecol=79, c=0;
+       
+       printf("{");
+       for (i=0; i<hash->size; i++) {
+               if (hash->table[i].val == CELL_UNUSED) {
+                       printf("--u-");
+               } else if (hash->table[i].val == CELL_FREE) {
+                       printf("--f-");
+               } else  {
+                       printf("%2x", (intptr_t)hash->table[i].key);
+               }
+               
+               if (i != hash->size-1)
+                       printf(", ");
+               
+               c += 6;
+               
+               if (c >= linecol) {
+                       printf("\n ");
+                       c = 0;
+               }
+       }
+       
+       fflush(stdout);
+}
+
 BMEdgeHit *knife_edge_tri_isect(knifetool_opdata *kcd, BMBVHTree *bmtree, float v1[3], 
-                              float v2[3], float v3[3], bglMats *mats, int *count)
+                              float v2[3], float v3[3], SmallHash *ehash, bglMats *mats, int *count)
 {
        BVHTree *tree2 = BLI_bvhtree_new(3, FLT_EPSILON*4, 8, 8), *tree = BMBVH_BVHTree(bmtree);
        BMEdgeHit *edges = NULL;
        BLI_array_declare(edges);
-       SmallHash hash, *ehash = &hash;
        BVHTreeOverlap *results, *result;
-       BMLoop *l, **ls;
+       BMLoop **ls;
        float cos[9], uv[3], lambda;
        int tot=0, i, j;
        
-       BLI_smallhash_init(ehash);
-       
        copy_v3_v3(cos, v1);
        copy_v3_v3(cos+3, v2);
        copy_v3_v3(cos+6, v3);
@@ -712,9 +749,10 @@ BMEdgeHit *knife_edge_tri_isect(knifetool_opdata *kcd, BMBVHTree *bmtree, float
                ls = (BMLoop**)kcd->em->looptris[result->indexA];
                
                for (j=0; j<3; j++) {
-                       ListBase *lst = knife_get_face_kedges(kcd, ls[j]->f);
+                       BMLoop *l1 = ls[j];     
+                       ListBase *lst = knife_get_face_kedges(kcd, l1->f);
                        Ref *ref;
-                               
+                       
                        for (ref=lst->first; ref; ref=ref->next) {                      
                                KnifeEdge *kfe = ref->ref;
                                
@@ -725,13 +763,15 @@ BMEdgeHit *knife_edge_tri_isect(knifetool_opdata *kcd, BMBVHTree *bmtree, float
                                        mul_v3_fl(p, lambda);
                                        add_v3_v3(p, kfe->v1->co);
                                        
-                                       view3d_project_float_v3(kcd->ar, p, sp, kcd->projmat);
+                                       knife_project_v3(kcd, p, sp);
                                        view3d_unproject(mats, view, sp[0], sp[1], 0.0f);
+                                       mul_m4_v3(kcd->ob->imat, view);
+
                                        sub_v3_v3v3(view, p, view);
-                                       normalize_v3(view);
+                                       normalize_v3(view);;
        
                                        copy_v3_v3(no, view);
-                                       mul_v3_fl(no, -0.00001);
+                                       mul_v3_fl(no, -0.0003);
                                        
                                        /*go backwards toward view a bit*/
                                        add_v3_v3(p, no);
@@ -746,7 +786,7 @@ BMEdgeHit *knife_edge_tri_isect(knifetool_opdata *kcd, BMBVHTree *bmtree, float
                                                hit.f = kfe->basef;
                                                
                                                copy_v3_v3(hit.hit, p);
-                                               view3d_project_float_v3(kcd->ar, hit.hit, hit.shit, kcd->projmat);
+                                               knife_project_v3(kcd, hit.hit, hit.shit);
                                                
                                                BLI_array_append(edges, hit);
                                                BLI_smallhash_insert(ehash, (intptr_t)kfe, NULL);
@@ -756,8 +796,6 @@ BMEdgeHit *knife_edge_tri_isect(knifetool_opdata *kcd, BMBVHTree *bmtree, float
                }
        }
        
-       BLI_smallhash_release(ehash);
-       
        if (results)
                MEM_freeN(results);
        
@@ -765,15 +803,23 @@ BMEdgeHit *knife_edge_tri_isect(knifetool_opdata *kcd, BMBVHTree *bmtree, float
        return edges;
 }
 
+void knife_bgl_get_mats(knifetool_opdata *kcd, bglMats *mats)
+{
+       bgl_get_mats(mats);
+       //copy_m4_m4(mats->modelview, kcd->vc.rv3d->viewmat);
+       //copy_m4_m4(mats->projection, kcd->vc.rv3d->winmat);
+}
+
 /*finds (visible) edges that intersects the current screen drag line*/
 static void knife_find_line_hits(knifetool_opdata *kcd)
 {
        bglMats mats;
        BMEdgeHit *e1, *e2;
+       SmallHash hash, *ehash = &hash;
        float v1[3], v2[3], v3[3], v4[4], s1[3], s2[3], view[3];
        int i, c1, c2;
        
-       bgl_get_mats(&mats);
+       knife_bgl_get_mats(kcd, &mats);
        
        if (kcd->linehits) {
                MEM_freeN(kcd->linehits);
@@ -782,8 +828,8 @@ static void knife_find_line_hits(knifetool_opdata *kcd)
        }
        
        /*project screen line's 3d coordinates back into 2d*/
-       view3d_project_float_v3(kcd->ar, kcd->prevco, s1, kcd->projmat);
-       view3d_project_float_v3(kcd->ar, kcd->vertco, s2, kcd->projmat);
+       knife_project_v3(kcd, kcd->prevco, s1);
+       knife_project_v3(kcd, kcd->vertco, s2);
        
        if (len_v2v2(s1, s2) < 1)
                return;
@@ -802,9 +848,11 @@ static void knife_find_line_hits(knifetool_opdata *kcd)
        sub_v3_v3v3(view, v4, v1);
        normalize_v3(view);
        
+       BLI_smallhash_init(ehash);
+       
        /*test two triangles of sceen line's plane*/
-       e1 = knife_edge_tri_isect(kcd, kcd->bmbvh, v1, v2, v3, &mats, &c1);
-       e2 = knife_edge_tri_isect(kcd, kcd->bmbvh, v1, v3, v4, &mats, &c2);
+       e1 = knife_edge_tri_isect(kcd, kcd->bmbvh, v1, v2, v3, ehash, &mats, &c1);
+       e2 = knife_edge_tri_isect(kcd, kcd->bmbvh, v1, v3, v4, ehash, &mats, &c2);
        if (c1 && c2) {
                e1 = MEM_reallocN(e1, sizeof(BMEdgeHit)*(c1+c2));
                memcpy(e1+c1, e2, sizeof(BMEdgeHit)*c2);
@@ -822,6 +870,8 @@ static void knife_find_line_hits(knifetool_opdata *kcd)
                
                lh->l = len_v2v2(lh->shit, s1) / len_v2v2(s2, s1);
        }
+       
+       BLI_smallhash_release(ehash);
 }
 
 static BMFace *knife_find_closest_face(knifetool_opdata *kcd, float co[3])
@@ -832,13 +882,13 @@ static BMFace *knife_find_closest_face(knifetool_opdata *kcd, float co[3])
        float mval[2];
        int dist = KMAXDIST; 
        
-       bgl_get_mats(&mats);
+       knife_bgl_get_mats(kcd, &mats);
 
        mval[0] = kcd->vc.mval[0]; mval[1] = kcd->vc.mval[1];
        
        /*unproject to find view ray*/
        view3d_unproject(&mats, origin, mval[0], mval[1], 0.0f);
-       
+
        sub_v3_v3v3(ray, origin, kcd->vc.rv3d->viewinv[3]);
        normalize_v3(ray);
        
@@ -877,7 +927,7 @@ static int knife_sample_screen_density(knifetool_opdata *kcd, float radius)
                float dis;
                int c = 0;
                
-               view3d_project_float_v3(kcd->ar, co, sco, kcd->projmat);
+               knife_project_v3(kcd, co, sco);
                
                lst = knife_get_face_kedges(kcd, f);
                for (ref=lst->first; ref; ref=ref->next) {
@@ -887,7 +937,7 @@ static int knife_sample_screen_density(knifetool_opdata *kcd, float radius)
                        for (i=0; i<2; i++) {
                                KnifeVert *kfv = i ? kfe->v2 : kfe->v1;
                                
-                               view3d_project_float_v3(kcd->ar, kfv->co, kfv->sco, kcd->projmat);
+                               knife_project_v3(kcd, kfv->co, kfv->sco);
                                
                                dis = len_v2v2(kfv->sco, sco);
                                if (dis < radius) {
@@ -940,7 +990,7 @@ static KnifeEdge *knife_find_closest_edge(knifetool_opdata *kcd, float p[3], BMF
                Ref *ref;
                float dis, curdis=FLT_MAX;
                
-               view3d_project_float_v3(kcd->ar, co, sco, kcd->projmat);
+               knife_project_v3(kcd, co, sco);
                
                /*look through all edges associated with this face*/
                lst = knife_get_face_kedges(kcd, f);
@@ -948,8 +998,8 @@ static KnifeEdge *knife_find_closest_edge(knifetool_opdata *kcd, float p[3], BMF
                        KnifeEdge *kfe = ref->ref;
                        
                        /*project edge vertices into screen space*/
-                       view3d_project_float_v3(kcd->ar, kfe->v1->co, kfe->v1->sco, kcd->projmat);
-                       view3d_project_float_v3(kcd->ar, kfe->v2->co, kfe->v2->sco, kcd->projmat);
+                       knife_project_v3(kcd, kfe->v1->co, kfe->v1->sco);
+                       knife_project_v3(kcd, kfe->v2->co, kfe->v2->sco);
 
                        dis = dist_to_line_segment_v2(sco, kfe->v1->sco, kfe->v2->sco);
                        if (dis < curdis && dis < maxdist) {
@@ -1006,7 +1056,7 @@ static KnifeVert *knife_find_closest_vert(knifetool_opdata *kcd, float p[3], BMF
                KnifeVert *curv = NULL;
                float dis, curdis=FLT_MAX;
                
-               view3d_project_float_v3(kcd->ar, co, sco, kcd->projmat);
+               knife_project_v3(kcd, co, sco);
                
                lst = knife_get_face_kedges(kcd, f);
                for (ref=lst->first; ref; ref=ref->next) {
@@ -1016,7 +1066,7 @@ static KnifeVert *knife_find_closest_vert(knifetool_opdata *kcd, float p[3], BMF
                        for (i=0; i<2; i++) {
                                KnifeVert *kfv = i ? kfe->v2 : kfe->v1;
                                
-                               view3d_project_float_v3(kcd->ar, kfv->co, kfv->sco, kcd->projmat);
+                               knife_project_v3(kcd, kfv->co, kfv->sco);
                                
                                dis = len_v2v2(kfv->sco, sco);
                                if (dis < curdis && dis < maxdist) {
@@ -1241,6 +1291,24 @@ void knifenet_fill_faces(knifetool_opdata *kcd)
                        BMO_ClearFlag(bm, e, MARK);
        }
 
+       BM_ITER(f, &bmiter, bm, BM_FACES_OF_MESH, NULL) {
+               BMIter eiter;
+               
+               if (!BMO_TestFlag(bm, f, DEL))
+                       continue;
+               
+               BM_ITER(e, &eiter, bm, BM_EDGES_OF_FACE, f) {
+                       BMIter liter;
+                       BMLoop *l;
+                       
+                       BMO_SetFlag(bm, e, MARK);
+                       
+                       BM_ITER(l, &liter, bm, BM_LOOPS_OF_EDGE, e) {
+                               BMINDEX_SET(e, BMINDEX_GET(e)|BMINDEX_GET(l->f));
+                       }
+               }
+       }
+
        BMO_Flag_To_Slot(bm, &bmop, "edges", MARK, BM_EDGE);
        BMO_Flag_To_Slot(bm, &bmop, "excludefaces", DEL, BM_FACE);
        
@@ -1390,10 +1458,33 @@ static void knifetool_finish(bContext *C, wmOperator *op)
        knifenet_fill_faces(kcd);
 }
 
+/*copied from paint_image.c*/
+static int project_knife_view_clip(View3D *v3d, RegionView3D *rv3d, float *clipsta, float *clipend)
+{
+       int orth= get_view3d_cliprange(v3d, rv3d, clipsta, clipend);
+
+       if (orth) { /* only needed for ortho */
+               float fac = 2.0f / ((*clipend) - (*clipsta));
+               *clipsta *= fac;
+               *clipend *= fac;
+       }
+
+       return orth;
+}
+
 void knife_recalc_projmat(knifetool_opdata *kcd)
 {
+       ARegion *ar = CTX_wm_region(kcd->C);
+       
+       if (!ar)
+               return;
+       
        invert_m4_m4(kcd->ob->imat, kcd->ob->obmat);
-       view3d_get_object_project_mat(kcd->ar->regiondata, kcd->ob, kcd->projmat);      
+       view3d_get_object_project_mat(ar->regiondata, kcd->ob, kcd->projmat);
+       //mul_m4_m4m4(kcd->projmat, kcd->vc.rv3d->viewmat, kcd->vc.rv3d->winmat);
+       
+       kcd->is_ortho = project_knife_view_clip(kcd->vc.v3d, kcd->vc.rv3d, 
+                                               &kcd->clipsta, &kcd->clipend);
 }
 
 /* called when modal loop selection is done... */
@@ -1437,6 +1528,7 @@ static int knifetool_init (bContext *C, wmOperator *op, int do_cut)
        
        /* assign the drawing handle for drawing preview line... */
        kcd->ar= CTX_wm_region(C);
+       kcd->C = C;
        kcd->draw_handle= ED_region_draw_cb_activate(kcd->ar->type, knifetool_draw, kcd, REGION_DRAW_POST_VIEW);
        em_setup_viewcontext(C, &kcd->vc);
 
@@ -1490,7 +1582,16 @@ static int knifetool_invoke (bContext *C, wmOperator *op, wmEvent *evt)
 
 static int knifetool_modal (bContext *C, wmOperator *op, wmEvent *event)
 {
+       Object *obedit;
        knifetool_opdata *kcd= op->customdata;
+       
+       if (!C) {
+               return OPERATOR_FINISHED;
+       }
+       
+       obedit = CTX_data_edit_object(C);
+       if (!obedit || obedit->type != OB_MESH || ((Mesh*)obedit->data)->edit_btmesh != kcd->em)
+               return OPERATOR_FINISHED;
 
        view3d_operator_needs_opengl(C);
 
@@ -1556,7 +1657,10 @@ static int knifetool_modal (bContext *C, wmOperator *op, wmEvent *event)
                case ZKEY:
                        if (event->ctrl)
                                return OPERATOR_RUNNING_MODAL;
-               }                       
+               }       
+               case KKEY:
+                       if (!event->ctrl && !event->alt && !event->shift)
+                               return OPERATOR_RUNNING_MODAL;
        }
        
        /* keep going until the user confirms */
@@ -1579,64 +1683,3 @@ void MESH_OT_knifetool (wmOperatorType *ot)
        /* flags */
        ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO|OPTYPE_BLOCKING;
 }
-#endif
-
-/*
-       if (0) {
-               ListBase fgroups[30];
-               BMEdge *e;
-               
-               memset(fgroups, 0, sizeof(fgroups));
-               BM_ITER(f, &bmiter, kcd->em->bm, BM_FACES_OF_MESH, NULL) {
-                       Ref *ref = BLI_mempool_alloc(kcd->refs);
-                       int i;
-                       
-                       ref->ref = f;
-                       for (i=0; i<30; i++) {
-                               if ((1<<i) == BMINDEX_GET(f))
-                                       break;
-                       }
-                       
-                       BLI_addtail(&fgroups[i], ref);
-               }
-               
-               BM_ITER(e, &bmiter, kcd->em->bm, BM_EDGES_OF_MESH, NULL) {
-                       Ref *ref;
-                       int group = 0;
-                       
-                       if (!BMO_InMap(kcd->em->bm, &bmop, "restrict", e))
-                                       continue;
-                       
-                       group = BMO_Get_MapInt(kcd->em->bm, &bmop, "restrict", e);
-                       
-                       for (i=0; i<30; i++) {
-                               if ((1<<i) & group) {
-                                       float co[3];
-                                       BMVert *v1, *v2;
-
-                                       add_v3_v3v3(co, e->v1->co, e->v2->co);
-                                       mul_v3_fl(co, 0.5f);
-                                       
-                                       v1 = BM_Make_Vert(kcd->em->bm, co, NULL);
-                                       
-                                       for (ref=fgroups[i].first; ref; ref=ref->next) {
-                                               BMFace *f = ref->ref;
-                                               BMLoop *l;
-                                               BMIter liter;
-                                               BMEdge *e2;
-                                               
-                                               zero_v3(co);
-                                               BM_ITER(l, &liter, kcd->em->bm, BM_LOOPS_OF_FACE, f) {
-                                                       add_v3_v3(co, l->v->co);
-                                               }
-                                               mul_v3_fl(co, 1.0f/(float)f->len);
-                                               
-                                               v2 = BM_Make_Vert(kcd->em->bm, co, NULL);
-                                               e2 = BM_Make_Edge(kcd->em->bm, v1, v2, NULL, 0);
-                                       }
-                               }
-                       }
-               }
-       }
-  */