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