4 * ***** BEGIN GPL LICENSE BLOCK *****
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.
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.
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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 * The Original Code is Copyright (C) 2004 by Blender Foundation.
21 * All rights reserved.
23 * The Original Code is: all of this file.
25 * Contributor(s): none yet.
27 * ***** END GPL LICENSE BLOCK *****
32 editmesh_loop: tools with own drawing subloops, select, knife, subdiv
40 #include "MEM_guardedalloc.h"
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"
51 #include "BLI_blenlib.h"
52 #include "BLI_arithb.h"
53 #include "BLI_editVert.h"
54 #include "BLI_ghash.h"
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"
62 #include "BKE_object.h"
63 #include "BKE_utildefines.h"
69 #include "RNA_access.h"
70 #include "RNA_define.h"
76 #include "ED_screen.h"
77 #include "ED_view3d.h"
79 #include "mesh_intern.h"
81 /* **** XXX ******** */
82 static void BIF_undo_push() {}
83 static void BIF_undo() {}
84 static void error() {}
85 static int qtest() {return 0;}
86 /* **** XXX ******** */
90 static void edgering_sel(EditMesh *em, EditEdge *startedge, int select, int previewlines)
98 /* in eed->f1 we put the valence (amount of faces in edge) */
99 /* in eed->f2 we put tagged flag as correct loop */
100 /* in efa->f1 we put tagged flag as correct to select */
102 for(eed= em->edges.first; eed; eed= eed->next) {
106 for(efa= em->faces.first; efa; efa= efa->next) {
112 if(efa->e4) efa->e4->f1++;
122 for(efa= em->faces.first; efa; efa= efa->next) {
123 if(efa->e4 && efa->f1==0 && efa->h == 0) { // not done quad
124 if(efa->e1->f1<=2 && efa->e2->f1<=2 && efa->e3->f1<=2 && efa->e4->f1<=2) { // valence ok
126 // if edge tagged, select opposing edge and mark face ok
132 else if(efa->e2->f2) {
152 if(previewlines > 0 && select == 0){
153 // XXX persp(PERSP_VIEW);
154 // XXX glPushMatrix();
155 // XXX mymultmatrix(obedit->obmat);
157 for(efa= em->faces.first; efa; efa= efa->next) {
158 if(efa->v4 == NULL) { continue; }
160 if(efa->e1->f2 == 1){
161 if(efa->e1->h == 1 || efa->e3->h == 1 )
168 } else if(efa->e2->f2 == 1){
169 if(efa->e2->h == 1 || efa->e4->h == 1)
177 for(i=1;i<=previewlines;i++){
178 co[0][0] = (v[0][1]->co[0] - v[0][0]->co[0])*(i/((float)previewlines+1))+v[0][0]->co[0];
179 co[0][1] = (v[0][1]->co[1] - v[0][0]->co[1])*(i/((float)previewlines+1))+v[0][0]->co[1];
180 co[0][2] = (v[0][1]->co[2] - v[0][0]->co[2])*(i/((float)previewlines+1))+v[0][0]->co[2];
182 co[1][0] = (v[1][1]->co[0] - v[1][0]->co[0])*(i/((float)previewlines+1))+v[1][0]->co[0];
183 co[1][1] = (v[1][1]->co[1] - v[1][0]->co[1])*(i/((float)previewlines+1))+v[1][0]->co[1];
184 co[1][2] = (v[1][1]->co[2] - v[1][0]->co[2])*(i/((float)previewlines+1))+v[1][0]->co[2];
185 glColor3ub(255, 0, 255);
187 glVertex3f(co[0][0],co[0][1],co[0][2]);
188 glVertex3f(co[1][0],co[1][1],co[1][2]);
196 /* (de)select the edges */
197 for(eed= em->edges.first; eed; eed= eed->next) {
198 if(eed->f2) EM_select_edge(eed, select);
202 void CutEdgeloop(Object *obedit, wmOperator *op, EditMesh *em, int numcuts)
204 ViewContext vc; // XXX
205 EditEdge *nearest=NULL, *eed;
207 int keys = 0, holdnum=0, selectmode, dist;
208 short mvalo[2] = {0,0}, mval[2];
209 short event=0, val, choosing=1, cancel=0, cuthalf = 0, smooth=0;
213 selectmode = em->selectmode;
215 if(em->selectmode & SCE_SELECT_FACE){
216 em->selectmode = SCE_SELECT_EDGE;
217 EM_selectmode_set(em);
221 BIF_undo_push("Loopcut Begin");
222 while(choosing && !cancel){
223 // XXX getmouseco_areawin(mval);
224 if (mval[0] != mvalo[0] || mval[1] != mvalo[1]) {
228 nearest = findnearestedge(&vc, &dist); // returns actual distance in dist
229 // scrarea_do_windraw(curarea); // after findnearestedge, backbuf!
231 sprintf(msg,"Number of Cuts: %d",numcuts);
233 sprintf(msg,"%s (S)mooth: on",msg);
235 sprintf(msg,"%s (S)mooth: off",msg);
239 /* Need to figure preview */
241 edgering_sel(em, nearest, 0, numcuts);
243 // XXX screen_swapbuffers();
245 /* backbuffer refresh for non-apples (no aux) */
247 // XXX if(G.vd->drawtype>OB_WIRE && (G.vd->flag & V3D_ZBUF_SELECT)) {
248 // backdrawview3d(0);
252 else PIL_sleep_ms(10); // idle
258 // XXX event= extern_qread(&val);
259 if(val && (event == MOUSEX || event == MOUSEY)){ ; }
260 else if(val && ((event==LEFTMOUSE || event==RETKEY) || (event == MIDDLEMOUSE || event==PADENTER)))
262 if(event == MIDDLEMOUSE){
270 else if(val && (event==ESCKEY || event==RIGHTMOUSE ))
276 else if(val && (event==PADPLUSKEY || event==WHEELUPMOUSE))
281 else if(val && (event==PADMINUS || event==WHEELDOWNMOUSE))
288 else if(val && event==SKEY)
290 if(smooth){smooth=0;}
331 if(holdnum >= 0 && numcuts*10 < 130){
332 if(keys == 0){ // first level numeric entry
337 } else if(keys > 0){//highrt level numeric entry
342 } else if (holdnum == -2){// backspace
353 } // End Numeric Entry
354 } //End while(qtest())
360 /* clean selection */
361 for(eed=em->edges.first; eed; eed = eed->next){
362 EM_select_edge(eed,0);
364 /* select edge ring */
365 edgering_sel(em, nearest, 1, 0);
367 /* now cut the loops */
370 // XXX if(fbutton(&fac, 0.0f, 5.0f, 10, 10, "Smooth:")==0) return;
372 esubdivideflag(obedit, em, SELECT,fac,0,B_SMOOTH,numcuts,SUBDIV_SELECT_LOOPCUT);
374 esubdivideflag(obedit, em, SELECT,0,0,0,numcuts,SUBDIV_SELECT_LOOPCUT);
376 /* if this was a single cut, enter edgeslide mode */
377 if(numcuts == 1 && hasHidden == 0){
379 EdgeSlide(em, op, 1,0.0);
381 if(EdgeSlide(em, op, 0,0.0) == -1){
387 if(em->selectmode != selectmode){
388 em->selectmode = selectmode;
389 EM_selectmode_set(em);
392 // DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
397 /* *************** LOOP SELECT ************* */
399 static short edgeFaces(EditMesh *em, EditEdge *e)
401 EditFace *search=NULL;
404 search = em->faces.first;
406 if((search->e1 == e || search->e2 == e) || (search->e3 == e || search->e4 == e))
408 search = search->next;
416 /* ***************** TRAIL ************************
418 Read a trail of mouse coords and return them as an array of CutCurve structs
419 len returns number of mouse coords read before commiting with RETKEY
420 It is up to the caller to free the block when done with it,
422 XXX Is only used here, so local inside this file (ton)
425 #define TRAIL_POLYLINE 1 /* For future use, They don't do anything yet */
426 #define TRAIL_FREEHAND 2
427 #define TRAIL_MIXED 3 /* (1|2) */
429 #define TRAIL_MIDPOINTS 8
431 typedef struct CutCurve {
437 /* ******************************************************************** */
438 /* Knife Subdivide Tool. Subdivides edges intersected by a mouse trail
441 Currently mapped to KKey when in MeshEdit mode.
443 Hit Shift K, Select Centers or Exact
444 Hold LMB down to draw path, hit RETKEY.
445 ESC cancels as expected.
447 Contributed by Robert Wenzlaff (Det. Thorn).
450 - non modal (no menu before cutting)
451 - exit on mouse release
452 - polygon/segment drawing can become handled by WM cb later
456 #define KNIFE_EXACT 1
457 #define KNIFE_MIDPOINT 2
458 #define KNIFE_MULTICUT 3
460 static EnumPropertyItem knife_items[]= {
461 {KNIFE_EXACT, "EXACT", 0, "Exact", ""},
462 {KNIFE_MIDPOINT, "MIDPOINTS", 0, "Midpoints", ""},
463 {KNIFE_MULTICUT, "MULTICUT", 0, "Multicut", ""},
464 {0, NULL, 0, NULL, NULL}
467 /* seg_intersect() Determines if and where a mouse trail intersects an EditEdge */
469 static float seg_intersect(EditEdge *e, CutCurve *c, int len, char mode, struct GHash *gh)
471 #define MAXSLOPE 100000
472 float x11, y11, x12=0, y12=0, x2max, x2min, y2max;
473 float y2min, dist, lastdist=0, xdiff2, xdiff1;
474 float m1, b1, m2, b2, x21, x22, y21, y22, xi;
475 float yi, x1min, x1max, y1max, y1min, perc=0;
480 threshold = 0.000001; /*tolerance for vertex intersection*/
481 // XXX threshold = scene->toolsettings->select_thresh / 100;
483 /* Get screen coords of verts */
484 scr = BLI_ghash_lookup(gh, e->v1);
488 scr = BLI_ghash_lookup(gh, e->v2);
495 b2= ((x22*y21)-(x21*y22))/xdiff2;
498 m2=MAXSLOPE; /* Verticle slope */
502 /*check for *exact* vertex intersection first*/
503 if(mode!=KNIFE_MULTICUT){
504 for (i=0; i<len; i++){
517 if((x11 == x21 && y11 == y21) || (x12 == x21 && y12 == y21)){
523 else if((x11 == x22 && y11 == y22) || (x12 == x22 && y12 == y22)){
531 /*now check for edge interesect (may produce vertex intersection as well)*/
532 for (i=0; i<len; i++){
544 /* Perp. Distance from point to line */
545 if (m2!=MAXSLOPE) dist=(y12-m2*x12-b2);/* /sqrt(m2*m2+1); Only looking for */
546 /* change in sign. Skip extra math */
549 if (i==0) lastdist=dist;
551 /* if dist changes sign, and intersect point in edge's Bound Box*/
552 if ((lastdist*dist)<=0){
553 xdiff1=(x12-x11); /* Equation of line between last 2 points */
556 b1= ((x12*y11)-(x11*y12))/xdiff1;
562 x2max=MAX2(x21,x22)+0.001; /* prevent missed edges */
563 x2min=MIN2(x21,x22)-0.001; /* due to round off error */
564 y2max=MAX2(y21,y22)+0.001;
565 y2min=MIN2(y21,y22)-0.001;
567 /* Found an intersect, calc intersect point */
568 if (m1==m2){ /* co-incident lines */
569 /* cut at 50% of overlap area*/
570 x1max=MAX2(x11, x12);
571 x1min=MIN2(x11, x12);
572 xi= (MIN2(x2max,x1max)+MAX2(x2min,x1min))/2.0;
574 y1max=MAX2(y11, y12);
575 y1min=MIN2(y11, y12);
576 yi= (MIN2(y2max,y1max)+MAX2(y2min,y1min))/2.0;
578 else if (m2==MAXSLOPE){
582 else if (m1==MAXSLOPE){
588 yi=(b1*m2-m1*b2)/(m2-m1);
591 /* Intersect inside bounding box of edge?*/
592 if ((xi>=x2min)&&(xi<=x2max)&&(yi<=y2max)&&(yi>=y2min)){
593 /*test for vertex intersect that may be 'close enough'*/
594 if(mode!=KNIFE_MULTICUT){
595 if(xi <= (x21 + threshold) && xi >= (x21 - threshold)){
596 if(yi <= (y21 + threshold) && yi >= (y21 - threshold)){
602 if(xi <= (x22 + threshold) && xi >= (x22 - threshold)){
603 if(yi <= (y22 + threshold) && yi >= (y22 - threshold)){
610 if ((m2<=1.0)&&(m2>=-1.0)) perc = (xi-x21)/(x22-x21);
611 else perc=(yi-y21)/(y22-y21); /*lower slope more accurate*/
612 //isect=32768.0*(perc+0.0000153); /* Percentage in 1/32768ths */
625 static int knife_cut_exec(bContext *C, wmOperator *op)
627 Scene *scene = CTX_data_scene(C);
628 Object *obedit= CTX_data_edit_object(C);
629 EditMesh *em= BKE_mesh_get_editmesh(((Mesh *)obedit->data));
630 ARegion *ar= CTX_wm_region(C);
633 CutCurve curve[MAX_CUTS];
638 short numcuts=1, mode= RNA_int_get(op->ptr, "type");
640 if (EM_nvertices_selected(em) < 2) {
641 error("No edges are selected to operate on");
642 BKE_mesh_end_editmesh(obedit->data, em);
643 return OPERATOR_CANCELLED;;
646 /* get the cut curve */
647 RNA_BEGIN(op->ptr, itemptr, "path") {
649 RNA_float_get_array(&itemptr, "loc", (float *)&curve[len]);
651 if(len>= MAX_CUTS) break;
656 BKE_mesh_end_editmesh(obedit->data, em);
657 return OPERATOR_CANCELLED;
660 /*store percentage of edge cut for KNIFE_EXACT here.*/
661 for(eed=em->edges.first; eed; eed= eed->next)
664 /*the floating point coordinates of verts in screen space will be stored in a hash table according to the vertices pointer*/
665 gh = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp);
666 for(eve=em->verts.first; eve; eve=eve->next){
667 scr = MEM_mallocN(sizeof(float)*2, "Vertex Screen Coordinates");
668 VECCOPY(co, eve->co);
670 Mat4MulVec4fl(obedit->obmat, co);
671 project_float(ar, co, scr);
672 BLI_ghash_insert(gh, eve, scr);
673 eve->f1 = 0; /*store vertex intersection flag here*/
677 eed= em->edges.first;
679 if( eed->v1->f & eed->v2->f & SELECT ){ // NOTE: uses vertex select, subdiv doesnt do edges yet
680 isect= seg_intersect(eed, curve, len, mode, gh);
681 if (isect!=0.0f) eed->f2= 1;
684 //printf("isect=%i\n", isect);
693 if (mode==KNIFE_MIDPOINT) esubdivideflag(obedit, em, SELECT, 0, 0, B_KNIFE, 1, SUBDIV_SELECT_ORIG);
694 else if (mode==KNIFE_MULTICUT) esubdivideflag(obedit, em, SELECT, 0, 0, B_KNIFE, numcuts, SUBDIV_SELECT_ORIG);
695 else esubdivideflag(obedit, em, SELECT, 0, 0, B_KNIFE|B_PERCENTSUBD, 1, SUBDIV_SELECT_ORIG);
704 BLI_ghash_free(gh, NULL, (GHashValFreeFP)MEM_freeN);
706 BKE_mesh_end_editmesh(obedit->data, em);
708 DAG_object_flush_update(scene, obedit, OB_RECALC_DATA);
709 WM_event_add_notifier(C, NC_OBJECT|ND_GEOM_SELECT, obedit);
711 return OPERATOR_FINISHED;
715 void MESH_OT_knife_cut(wmOperatorType *ot)
719 ot->name= "Knife Cut";
720 ot->description= "Cut selected edges and faces into parts.";
721 ot->idname= "MESH_OT_knife_cut";
723 ot->invoke= WM_gesture_lines_invoke;
724 ot->modal= WM_gesture_lines_modal;
725 ot->exec= knife_cut_exec;
727 ot->poll= EM_view3d_poll;
730 ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
732 RNA_def_enum(ot->srna, "type", knife_items, KNIFE_EXACT, "Type", "");
733 prop= RNA_def_property(ot->srna, "path", PROP_COLLECTION, PROP_NONE);
734 RNA_def_property_struct_runtime(prop, &RNA_OperatorMousePath);
737 RNA_def_int(ot->srna, "cursor", BC_KNIFECURSOR, 0, INT_MAX, "Cursor", "", 0, INT_MAX);
740 /* ******************************************************* */