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