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