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