a8dd3837bc272e1b8b79a55408eb86d2ce89c7ce
[blender.git] / source / blender / editors / mesh / editmesh_loop.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * The Original Code is Copyright (C) 2004 by Blender Foundation.
21  * All rights reserved.
22  *
23  * The Original Code is: all of this file.
24  *
25  * Contributor(s): none yet.
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  */
29
30 /*
31
32 editmesh_loop: tools with own drawing subloops, select, knife, subdiv
33
34 */
35
36 #include <stdlib.h>
37 #include <string.h>
38 #include <math.h>
39
40 #include "MEM_guardedalloc.h"
41
42
43 #include "DNA_object_types.h"
44 #include "DNA_scene_types.h"
45 #include "DNA_screen_types.h"
46
47 #include "BLI_blenlib.h"
48 #include "BLI_math.h"
49 #include "BLI_utildefines.h"
50 #include "BLI_editVert.h"
51 #include "BLI_ghash.h"
52
53 #include "BKE_context.h"
54 #include "BKE_depsgraph.h"
55 #include "BKE_mesh.h"
56 #include "BKE_array_mallocn.h"
57
58 #include "PIL_time.h"
59
60 #include "BIF_gl.h"
61
62 #include "RNA_access.h"
63 #include "RNA_define.h"
64
65 #include "WM_api.h"
66 #include "WM_types.h"
67
68 #include "ED_mesh.h"
69 #include "ED_view3d.h"
70
71 #include "mesh_intern.h"
72
73 /* **** XXX ******** */
74 static void BIF_undo_push(const char *UNUSED(arg)) {}
75 static void BIF_undo(void) {}
76 static void error(const char *UNUSED(arg)) {}
77 static int qtest(void) {return 0;}
78 /* **** XXX ******** */
79
80
81 /* New LoopCut */
82 static void edgering_sel(EditMesh *em, EditEdge *startedge, int select, int previewlines)
83 {
84         EditEdge *eed;
85         EditFace *efa;
86         EditVert *v[2][2];
87         float co[2][3];
88         int looking= 1,i;
89         
90         /* in eed->f1 we put the valence (amount of faces in edge) */
91         /* in eed->f2 we put tagged flag as correct loop */
92         /* in efa->f1 we put tagged flag as correct to select */
93
94         for(eed= em->edges.first; eed; eed= eed->next) {
95                 eed->f1= 0;
96                 eed->f2= 0;
97         }
98         for(efa= em->faces.first; efa; efa= efa->next) {
99                 efa->f1= 0;
100                 if(efa->h==0) {
101                         efa->e1->f1++;
102                         efa->e2->f1++;
103                         efa->e3->f1++;
104                         if(efa->e4) efa->e4->f1++;
105                 }
106         }
107         
108         // tag startedge OK
109         startedge->f2= 1;
110         
111         while(looking) {
112                 looking= 0;
113                 
114                 for(efa= em->faces.first; efa; efa= efa->next) {
115                         if(efa->e4 && efa->f1==0 && efa->h == 0) {      // not done quad
116                                 if(efa->e1->f1<=2 && efa->e2->f1<=2 && efa->e3->f1<=2 && efa->e4->f1<=2) { // valence ok
117
118                                         // if edge tagged, select opposing edge and mark face ok
119                                         if(efa->e1->f2) {
120                                                 efa->e3->f2= 1;
121                                                 efa->f1= 1;
122                                                 looking= 1;
123                                         }
124                                         else if(efa->e2->f2) {
125                                                 efa->e4->f2= 1;
126                                                 efa->f1= 1;
127                                                 looking= 1;
128                                         }
129                                         if(efa->e3->f2) {
130                                                 efa->e1->f2= 1;
131                                                 efa->f1= 1;
132                                                 looking= 1;
133                                         }
134                                         if(efa->e4->f2) {
135                                                 efa->e2->f2= 1;
136                                                 efa->f1= 1;
137                                                 looking= 1;
138                                         }
139                                 }
140                         }
141                 }
142         }
143         
144         if(previewlines > 0 && select == 0){
145 // XXX                  persp(PERSP_VIEW);
146 // XXX                  glPushMatrix();
147 // XXX                  mymultmatrix(obedit->obmat);
148
149                         for(efa= em->faces.first; efa; efa= efa->next) {
150                                 if(efa->v4 == NULL) {  continue; }
151                                 if(efa->h == 0){
152                                         if(efa->e1->f2 == 1){
153                                                 if(efa->e1->h == 1 || efa->e3->h == 1 )
154                                                         continue;
155                                                 
156                                                 v[0][0] = efa->v1;
157                                                 v[0][1] = efa->v2;
158                                                 v[1][0] = efa->v4;
159                                                 v[1][1] = efa->v3;
160                                         } else if(efa->e2->f2 == 1){
161                                                 if(efa->e2->h == 1 || efa->e4->h == 1)
162                                                         continue;
163                                                 v[0][0] = efa->v2;
164                                                 v[0][1] = efa->v3;
165                                                 v[1][0] = efa->v1;
166                                                 v[1][1] = efa->v4;                                      
167                                         } else { continue; }
168                                                                                   
169                                         for(i=1;i<=previewlines;i++){
170                                                 co[0][0] = (v[0][1]->co[0] - v[0][0]->co[0])*(i/((float)previewlines+1))+v[0][0]->co[0];
171                                                 co[0][1] = (v[0][1]->co[1] - v[0][0]->co[1])*(i/((float)previewlines+1))+v[0][0]->co[1];
172                                                 co[0][2] = (v[0][1]->co[2] - v[0][0]->co[2])*(i/((float)previewlines+1))+v[0][0]->co[2];
173
174                                                 co[1][0] = (v[1][1]->co[0] - v[1][0]->co[0])*(i/((float)previewlines+1))+v[1][0]->co[0];
175                                                 co[1][1] = (v[1][1]->co[1] - v[1][0]->co[1])*(i/((float)previewlines+1))+v[1][0]->co[1];
176                                                 co[1][2] = (v[1][1]->co[2] - v[1][0]->co[2])*(i/((float)previewlines+1))+v[1][0]->co[2];                                        
177                                                 glColor3ub(255, 0, 255);
178                                                 glBegin(GL_LINES);      
179                                                 glVertex3f(co[0][0],co[0][1],co[0][2]);
180                                                 glVertex3f(co[1][0],co[1][1],co[1][2]);
181                                                 glEnd();
182                                         }
183                                 }
184                         }
185                         glPopMatrix();   
186         } else {        
187         
188         /* (de)select the edges */
189                 for(eed= em->edges.first; eed; eed= eed->next) {
190                 if(eed->f2) EM_select_edge(eed, select);
191                 }
192         }
193 }
194
195 static void CutEdgeloop(Object *obedit, wmOperator *op, EditMesh *em, int numcuts)
196 {
197         ViewContext vc; // XXX
198         EditEdge *nearest=NULL, *eed;
199         float fac;
200         int keys = 0, holdnum=0, selectmode, dist;
201         short mvalo[2] = {0, 0}, mval[2] = {0, 0};
202         short event=0, val, choosing=1, cancel=0, cuthalf = 0, smooth=0;
203         short hasHidden = 0;
204         char msg[128];
205         
206         selectmode = em->selectmode;
207                 
208         if(em->selectmode & SCE_SELECT_FACE){
209                 em->selectmode =  SCE_SELECT_EDGE;
210                 EM_selectmode_set(em);    
211         }
212         
213         
214         BIF_undo_push("Loopcut Begin");
215         while(choosing && !cancel){
216 // XXX          getmouseco_areawin(mval);
217                 if (mval[0] != mvalo[0] || mval[1] != mvalo[1]) {
218                         mvalo[0] = mval[0];
219                         mvalo[1] = mval[1];
220                         dist= 50;
221                         nearest = findnearestedge(&vc, &dist);  // returns actual distance in dist
222 //                      scrarea_do_windraw(curarea);    // after findnearestedge, backbuf!
223
224                         BLI_snprintf(msg, sizeof(msg),"Number of Cuts: %d (S)mooth: %s", numcuts, smooth ? "on":"off");
225                         
226 //                      headerprint(msg);
227                         /* Need to figure preview */
228                         if(nearest){
229                                 edgering_sel(em, nearest, 0, numcuts);
230                          }   
231 // XXX                  screen_swapbuffers();
232                         
233                 /* backbuffer refresh for non-apples (no aux) */
234 #ifndef __APPLE__
235 // XXX                  if(G.vd->drawtype>OB_WIRE && (G.vd->flag & V3D_ZBUF_SELECT)) {
236 //                              backdrawview3d(0);
237 //                      }
238 #endif
239                 }
240                 else PIL_sleep_ms(10);  // idle
241                 
242                 
243                 while(qtest()) 
244                 {
245                         val=0;
246 // XXX                  event= extern_qread(&val);
247                         if(val && (event ==  MOUSEX || event == MOUSEY)){ ; } 
248                         else if(val && ((event==LEFTMOUSE || event==RETKEY) || (event == MIDDLEMOUSE || event==PADENTER)))
249                         {
250                                 if(event == MIDDLEMOUSE){
251                                         cuthalf = 1;
252                                 }
253                                 if (nearest==NULL)
254                                         cancel = 1;
255                                 choosing=0;
256                                 mvalo[0] = -1;
257                         }
258                         else if(val && (event==ESCKEY || event==RIGHTMOUSE ))
259                         {
260                                 choosing=0;
261                                 cancel = 1;
262                                 mvalo[0] = -1;
263                         }
264                         else if(val && (event==PADPLUSKEY || event==WHEELUPMOUSE))
265                         {
266                                 numcuts++;
267                                 mvalo[0] = -1;
268                         }
269                         else if(val && (event==PADMINUS || event==WHEELDOWNMOUSE))
270                         {
271                                 if(numcuts > 1){
272                                         numcuts--;
273                                         mvalo[0] = -1;
274                                 } 
275                         }
276                         else if(val && event==SKEY)
277                         {
278                                 if(smooth){smooth=0;} 
279                                 else { smooth=1; }
280                                 mvalo[0] = -1;
281                         }
282                         
283                         else if(val){
284                                 holdnum = -1;
285                                 switch(event){
286                                         case PAD9:
287                                         case NINEKEY:
288                                                 holdnum = 9; break;
289                                         case PAD8:
290                                         case EIGHTKEY:
291                                                 holdnum = 8;break;
292                                         case PAD7:
293                                         case SEVENKEY:
294                                                 holdnum = 7;break;
295                                         case PAD6:
296                                         case SIXKEY:
297                                                 holdnum = 6;break;
298                                         case PAD5:
299                                         case FIVEKEY:
300                                                 holdnum = 5;break;
301                                         case PAD4:
302                                         case FOURKEY:
303                                                 holdnum = 4;break;
304                                         case PAD3:
305                                         case THREEKEY:
306                                                 holdnum = 3; break;
307                                         case PAD2:
308                                         case TWOKEY:
309                                                 holdnum = 2;break;
310                                         case PAD1:
311                                         case ONEKEY:
312                                                 holdnum = 1; break;
313                                         case PAD0:
314                                         case ZEROKEY:
315                                                 holdnum = 0;break;      
316                                         case BACKSPACEKEY:
317                                                 holdnum = -2;break;                     
318                                 }
319                                 if(holdnum >= 0 && numcuts*10 < 130){
320                                         if(keys == 0){  // first level numeric entry
321                                                         if(holdnum > 0){
322                                                                         numcuts = holdnum;
323                                                                         keys++;         
324                                                         }
325                                         } else if(keys > 0){//highrt level numeric entry
326                                                         numcuts *= 10;
327                                                         numcuts += holdnum;
328                                                         keys++;         
329                                         }
330                                 } else if (holdnum == -2){// backspace
331                                         if (keys > 1){
332                                                 numcuts /= 10;          
333                                                 keys--;
334                                         } else {
335                                                 numcuts=1;
336                                                 keys = 0;
337                                         }
338                                 }
339                                 mvalo[0] = -1;
340                                 break;
341                         }  // End Numeric Entry                                         
342                 }  //End while(qtest())
343         }   // End Choosing
344
345         if(cancel){
346                 return;   
347         }
348         /* clean selection */
349         for(eed=em->edges.first; eed; eed = eed->next){
350                 EM_select_edge(eed,0);
351         }
352         /* select edge ring */
353         edgering_sel(em, nearest, 1, 0);
354         
355         /* now cut the loops */
356         if(smooth){
357                 fac= 1.0f;
358 // XXX          if(fbutton(&fac, 0.0f, 5.0f, 10, 10, "Smooth:")==0) return;
359                 fac= 0.292f*fac;                        
360                 esubdivideflag(obedit, em, SELECT,fac,0,B_SMOOTH,numcuts, SUBDIV_CORNER_PATH, SUBDIV_SELECT_LOOPCUT);
361         } else {
362                 esubdivideflag(obedit, em, SELECT,0,0,0,numcuts,SUBDIV_CORNER_PATH, SUBDIV_SELECT_LOOPCUT);
363         }
364         /* if this was a single cut, enter edgeslide mode */
365         if(numcuts == 1 && hasHidden == 0){
366                 if(cuthalf)
367                         EdgeSlide(em, op, 1,0.0);
368                 else {
369                         if(EdgeSlide(em, op, 0,0.0) == -1){
370                                 BIF_undo();
371                         }
372                 }
373         }
374         
375         if(em->selectmode !=  selectmode){
376                 em->selectmode = selectmode;
377                 EM_selectmode_set(em);
378         }       
379         
380 //      DAG_id_tag_update(obedit->data, 0);
381         return;
382 }
383
384
385 /* *************** LOOP SELECT ************* */
386 #if 0
387 static short edgeFaces(EditMesh *em, EditEdge *e)
388 {
389         EditFace *search=NULL;
390         short count = 0;
391         
392         search = em->faces.first;
393         while(search){
394                 if((search->e1 == e || search->e2 == e) || (search->e3 == e || search->e4 == e)) 
395                         count++;
396                 search = search->next;
397         }
398         return count;   
399 }
400 #endif
401
402
403
404 /*   ***************** TRAIL ************************
405
406 Read a trail of mouse coords and return them as an array of CutCurve structs
407 len returns number of mouse coords read before commiting with RETKEY   
408 It is up to the caller to free the block when done with it,
409
410 XXX Is only used here, so local inside this file (ton)
411  */
412
413 #define TRAIL_POLYLINE 1 /* For future use, They don't do anything yet */
414 #define TRAIL_FREEHAND 2
415 #define TRAIL_MIXED    3 /* (1|2) */
416 #define TRAIL_AUTO     4 
417 #define TRAIL_MIDPOINTS 8
418
419 typedef struct CutCurve {
420         float  x; 
421         float  y;
422 } CutCurve;
423
424
425 /* ******************************************************************** */
426 /* Knife Subdivide Tool.  Subdivides edges intersected by a mouse trail
427         drawn by user.
428         
429         Currently mapped to KKey when in MeshEdit mode.
430         Usage:
431                 Hit Shift K, Select Centers or Exact
432                 Hold LMB down to draw path, hit RETKEY.
433                 ESC cancels as expected.
434    
435         Contributed by Robert Wenzlaff (Det. Thorn).
436
437         2.5 revamp:
438         - non modal (no menu before cutting)
439         - exit on mouse release
440         - polygon/segment drawing can become handled by WM cb later
441
442 */
443
444 #define KNIFE_EXACT             1
445 #define KNIFE_MIDPOINT  2
446 #define KNIFE_MULTICUT  3
447
448 static EnumPropertyItem knife_items[]= {
449         {KNIFE_EXACT, "EXACT", 0, "Exact", ""},
450         {KNIFE_MIDPOINT, "MIDPOINTS", 0, "Midpoints", ""},
451         {KNIFE_MULTICUT, "MULTICUT", 0, "Multicut", ""},
452         {0, NULL, 0, NULL, NULL}
453 };
454
455 /* seg_intersect() Determines if and where a mouse trail intersects an EditEdge */
456
457 static float seg_intersect(EditEdge *e, CutCurve *c, int len, char mode, struct GHash *gh)
458 {
459 #define MAXSLOPE 100000
460         float  x11, y11, x12=0, y12=0, x2max, x2min, y2max;
461         float  y2min, dist, lastdist=0, xdiff2, xdiff1;
462         float  m1, b1, m2, b2, x21, x22, y21, y22, xi;
463         float  yi, x1min, x1max, y1max, y1min, perc=0; 
464         float  *scr;
465         float  threshold;
466         int  i;
467         
468         threshold = 0.000001; /*tolerance for vertex intersection*/
469         // XXX  threshold = scene->toolsettings->select_thresh / 100;
470         
471         /* Get screen coords of verts */
472         scr = BLI_ghash_lookup(gh, e->v1);
473         x21=scr[0];
474         y21=scr[1];
475         
476         scr = BLI_ghash_lookup(gh, e->v2);
477         x22=scr[0];
478         y22=scr[1];
479         
480         xdiff2=(x22-x21);  
481         if (xdiff2) {
482                 m2=(y22-y21)/xdiff2;
483                 b2= ((x22*y21)-(x21*y22))/xdiff2;
484         }
485         else {
486                 m2=MAXSLOPE;  /* Verticle slope  */
487                 b2=x22;      
488         }
489         
490         /*check for *exact* vertex intersection first*/
491         if(mode!=KNIFE_MULTICUT){
492                 for (i=0; i<len; i++){
493                         if (i>0){
494                                 x11=x12;
495                                 y11=y12;
496                         }
497                         else {
498                                 x11=c[i].x;
499                                 y11=c[i].y;
500                         }
501                         x12=c[i].x;
502                         y12=c[i].y;
503                         
504                         /*test e->v1*/
505                         if((x11 == x21 && y11 == y21) || (x12 == x21 && y12 == y21)){
506                                 e->v1->f1 = 1;
507                                 perc = 0;
508                                 return(perc);
509                         }
510                         /*test e->v2*/
511                         else if((x11 == x22 && y11 == y22) || (x12 == x22 && y12 == y22)){
512                                 e->v2->f1 = 1;
513                                 perc = 0;
514                                 return(perc);
515                         }
516                 }
517         }
518         
519         /*now check for edge interesect (may produce vertex intersection as well)*/
520         for (i=0; i<len; i++){
521                 if (i>0){
522                         x11=x12;
523                         y11=y12;
524                 }
525                 else {
526                         x11=c[i].x;
527                         y11=c[i].y;
528                 }
529                 x12=c[i].x;
530                 y12=c[i].y;
531                 
532                 /* Perp. Distance from point to line */
533                 if (m2!=MAXSLOPE) dist=(y12-m2*x12-b2);/* /sqrt(m2*m2+1); Only looking for */
534                         /* change in sign.  Skip extra math */  
535                 else dist=x22-x12;      
536                 
537                 if (i==0) lastdist=dist;
538                 
539                 /* if dist changes sign, and intersect point in edge's Bound Box*/
540                 if ((lastdist*dist)<=0){
541                         xdiff1=(x12-x11); /* Equation of line between last 2 points */
542                         if (xdiff1){
543                                 m1=(y12-y11)/xdiff1;
544                                 b1= ((x12*y11)-(x11*y12))/xdiff1;
545                         }
546                         else{
547                                 m1=MAXSLOPE;
548                                 b1=x12;
549                         }
550                         x2max=MAX2(x21,x22)+0.001; /* prevent missed edges   */
551                         x2min=MIN2(x21,x22)-0.001; /* due to round off error */
552                         y2max=MAX2(y21,y22)+0.001;
553                         y2min=MIN2(y21,y22)-0.001;
554                         
555                         /* Found an intersect,  calc intersect point */
556                         if (m1==m2){ /* co-incident lines */
557                                 /* cut at 50% of overlap area*/
558                                 x1max=MAX2(x11, x12);
559                                 x1min=MIN2(x11, x12);
560                                 xi= (MIN2(x2max,x1max)+MAX2(x2min,x1min))/2.0;  
561                                 
562                                 y1max=MAX2(y11, y12);
563                                 y1min=MIN2(y11, y12);
564                                 yi= (MIN2(y2max,y1max)+MAX2(y2min,y1min))/2.0;
565                         }                       
566                         else if (m2==MAXSLOPE){ 
567                                 xi=x22;
568                                 yi=m1*x22+b1;
569                         }
570                         else if (m1==MAXSLOPE){ 
571                                 xi=x12;
572                                 yi=m2*x12+b2;
573                         }
574                         else {
575                                 xi=(b1-b2)/(m2-m1);
576                                 yi=(b1*m2-m1*b2)/(m2-m1);
577                         }
578                         
579                         /* Intersect inside bounding box of edge?*/
580                         if ((xi>=x2min)&&(xi<=x2max)&&(yi<=y2max)&&(yi>=y2min)){
581                                 /*test for vertex intersect that may be 'close enough'*/
582                                 if(mode!=KNIFE_MULTICUT){
583                                         if(xi <= (x21 + threshold) && xi >= (x21 - threshold)){
584                                                 if(yi <= (y21 + threshold) && yi >= (y21 - threshold)){
585                                                         e->v1->f1 = 1;
586                                                         perc = 0;
587                                                         break;
588                                                 }
589                                         }
590                                         if(xi <= (x22 + threshold) && xi >= (x22 - threshold)){
591                                                 if(yi <= (y22 + threshold) && yi >= (y22 - threshold)){
592                                                         e->v2->f1 = 1;
593                                                         perc = 0;
594                                                         break;
595                                                 }
596                                         }
597                                 }
598                                 if ((m2<=1.0)&&(m2>=-1.0)) perc = (xi-x21)/(x22-x21);   
599                                 else perc=(yi-y21)/(y22-y21); /*lower slope more accurate*/
600                                 //isect=32768.0*(perc+0.0000153); /* Percentage in 1/32768ths */
601                                 
602                                 break;
603                         }
604                 }       
605                 lastdist=dist;
606         }
607         return(perc);
608
609
610
611 #define MAX_CUTS 256
612
613 static int knife_cut_exec(bContext *C, wmOperator *op)
614 {
615         Object *obedit= CTX_data_edit_object(C);
616         EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
617         ARegion *ar= CTX_wm_region(C);
618         EditEdge *eed;
619         EditVert *eve;
620         CutCurve curve[MAX_CUTS];
621         struct GHash *gh;
622         float isect=0.0;
623         float  *scr, co[4];
624         int len=0;
625         short numcuts= RNA_int_get(op->ptr, "num_cuts"); 
626         short mode= RNA_int_get(op->ptr, "type");
627 //      int corner_cut_pattern= RNA_enum_get(op->ptr,"corner_cut_pattern");
628         
629         /* edit-object needed for matrix, and ar->regiondata for projections to work */
630         if (ELEM3(NULL, obedit, ar, ar->regiondata))
631                 return OPERATOR_CANCELLED;
632         
633         if (EM_nvertices_selected(em) < 2) {
634                 error("No edges are selected to operate on");
635                 BKE_mesh_end_editmesh(obedit->data, em);
636                 return OPERATOR_CANCELLED;
637         }
638
639         /* get the cut curve */
640         RNA_BEGIN(op->ptr, itemptr, "path") {
641                 
642                 RNA_float_get_array(&itemptr, "loc", (float *)&curve[len]);
643                 len++;
644                 if(len>= MAX_CUTS) break;
645         }
646         RNA_END;
647         
648         if(len<2) {
649                 BKE_mesh_end_editmesh(obedit->data, em);
650                 return OPERATOR_CANCELLED;
651         }
652
653         /*store percentage of edge cut for KNIFE_EXACT here.*/
654         for(eed=em->edges.first; eed; eed= eed->next) 
655                 eed->tmp.fp = 0.0; 
656         
657         /*the floating point coordinates of verts in screen space will be stored in a hash table according to the vertices pointer*/
658         gh = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "knife_cut_exec gh");
659         for(eve=em->verts.first; eve; eve=eve->next){
660                 scr = MEM_mallocN(sizeof(float)*2, "Vertex Screen Coordinates");
661                 VECCOPY(co, eve->co);
662                 co[3]= 1.0;
663                 mul_m4_v4(obedit->obmat, co);
664                 project_float(ar, co, scr);
665                 BLI_ghash_insert(gh, eve, scr);
666                 eve->f1 = 0; /*store vertex intersection flag here*/
667         
668         }
669         
670         eed= em->edges.first;           
671         while(eed) {    
672                 if( eed->v1->f & eed->v2->f & SELECT ){         // NOTE: uses vertex select, subdiv doesnt do edges yet
673                         isect= seg_intersect(eed, curve, len, mode, gh);
674                         if (isect!=0.0f) eed->f2= 1;
675                         else eed->f2=0;
676                         eed->tmp.fp= isect;
677                 }
678                 else {
679                         eed->f2=0;
680                         eed->f1=0;
681                 }
682                 eed= eed->next;
683         }
684         
685         if (mode==KNIFE_MIDPOINT) esubdivideflag(obedit, em, SELECT, 0, 0, B_KNIFE, 1, SUBDIV_CORNER_INNERVERT, SUBDIV_SELECT_INNER);
686         else if (mode==KNIFE_MULTICUT) esubdivideflag(obedit, em, SELECT, 0, 0, B_KNIFE, numcuts, SUBDIV_CORNER_INNERVERT, SUBDIV_SELECT_INNER);
687         else esubdivideflag(obedit, em, SELECT, 0, 0, B_KNIFE|B_PERCENTSUBD, 1, SUBDIV_CORNER_INNERVERT, SUBDIV_SELECT_INNER);
688
689         eed=em->edges.first;
690         while(eed){
691                 eed->f2=0;
692                 eed->f1=0;
693                 eed=eed->next;
694         }       
695         
696         BLI_ghash_free(gh, NULL, (GHashValFreeFP)MEM_freeN);
697         
698         BKE_mesh_end_editmesh(obedit->data, em);
699
700         DAG_id_tag_update(obedit->data, 0);
701         WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
702
703         return OPERATOR_FINISHED;
704 }
705
706
707 void MESH_OT_knife_cut(wmOperatorType *ot)
708 {
709         PropertyRNA *prop;
710         
711         ot->name= "Knife Cut";
712         ot->description= "Cut selected edges and faces into parts";
713         ot->idname= "MESH_OT_knife_cut";
714         
715         ot->invoke= WM_gesture_lines_invoke;
716         ot->modal= WM_gesture_lines_modal;
717         ot->exec= knife_cut_exec;
718         
719         ot->poll= EM_view3d_poll;
720         
721         /* flags */
722         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
723         
724         RNA_def_enum(ot->srna, "type", knife_items, KNIFE_EXACT, "Type", "");
725         prop= RNA_def_property(ot->srna, "path", PROP_COLLECTION, PROP_NONE);
726         RNA_def_property_struct_runtime(prop, &RNA_OperatorMousePath);
727         RNA_def_int(ot->srna, "num_cuts", 1, 1, MAX_CUTS, "Number of Cuts", "Only for Multi-Cut", 1, MAX_CUTS);
728         // doesn't work atm.. RNA_def_enum(ot->srna, "corner_cut_pattern", corner_type_items, SUBDIV_CORNER_INNERVERT, "Corner Cut Pattern", "Topology pattern to use to fill a face after cutting across its corner");
729         
730         /* internal */
731         RNA_def_int(ot->srna, "cursor", BC_KNIFECURSOR, 0, INT_MAX, "Cursor", "", 0, INT_MAX);
732 }
733
734 /* ******************************************************* */
735