4
* ***** BEGIN GPL/BL DUAL 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. The Blender
10
* Foundation also sells licenses for use in proprietary software under
11
* the Blender License. See http://www.blender.org/BL/ for information
14
* This program is distributed in the hope that it will be useful,
15
* but WITHOUT ANY WARRANTY; without even the implied warranty of
16
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17
* GNU General Public License for more details.
19
* You should have received a copy of the GNU General Public License
20
* along with this program; if not, write to the Free Software Foundation,
21
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23
* The Original Code is Copyright (C) 2004 by NaN Holding BV.
24
* All rights reserved.
26
* The Original Code is: all of this file.
28
* Contributor(s): none yet.
30
* ***** END GPL/BL DUAL LICENSE BLOCK *****
35
editmesh_loop: tools with own drawing subloops, select, knife, subdiv
43
#include "MEM_guardedalloc.h"
46
#include "DNA_mesh_types.h"
47
#include "DNA_meshdata_types.h"
48
#include "DNA_object_types.h"
49
#include "DNA_scene_types.h"
50
#include "DNA_screen_types.h"
51
#include "DNA_view3d_types.h"
53
#include "BLI_blenlib.h"
54
#include "BLI_arithb.h"
55
#include "BLI_editVert.h"
57
#include "BKE_displist.h"
58
#include "BKE_global.h"
59
#include "BKE_library.h"
61
#include "BKE_object.h"
62
#include "BKE_utildefines.h"
64
#include "BIF_cursors.h"
65
#include "BIF_editmesh.h"
67
#include "BIF_glutil.h"
68
#include "BIF_graphics.h"
69
#include "BIF_interface.h"
70
#include "BIF_mywindow.h"
71
#include "BIF_screen.h"
72
#include "BIF_space.h"
73
#include "BIF_toolbox.h"
77
#include "BSE_drawview.h"
79
#include "BDR_drawobject.h"
80
#include "BDR_editobject.h"
88
/* next 2 includes for knife tool... shouldnt be! (ton) */
89
#include "GHOST_C-api.h"
93
/* *************** LOOP SELECT ************* */
95
static short edgeFaces(EditEdge *e){
96
EditMesh *em = G.editMesh;
97
EditFace *search=NULL;
100
search = em->faces.first;
102
if((search->e1 == e || search->e2 == e) || (search->e3 == e || search->e4 == e))
104
search = search->next;
109
/* this utility function checks to see if 2 edit edges share a face,
111
returns 0 if they do not, or if the function is passed the same edge 2 times
113
static short sharesFace(EditEdge* e1, EditEdge* e2)
115
EditMesh *em = G.editMesh;
116
EditFace *search=NULL;
117
search = em->faces.first;
123
((search->e1 == e1 || search->e2 == e1) || (search->e3 == e1 || search->e4 == e1)) &&
124
((search->e1 == e2 || search->e2 == e2) || (search->e3 == e2 || search->e4 == e2))
128
search = search->next;
132
/* This function selects a vertex loop based on a each succesive edge having a valance of 4
133
and not sharing a face with the previous edge */
135
/* It uses ->f flags still, which isn't causing bugs now, but better be put in ->f1 (ton) */
137
void vertex_loop_select()
139
EditMesh *em = G.editMesh;
140
EditVert *v1=NULL,*v2=NULL;
141
EditEdge *search=NULL,*startEdge=NULL,*valSearch = NULL,*nearest = NULL,*compEdge;
142
EditEdge *EdgeVal[5] = {NULL,NULL,NULL,NULL,NULL};
143
short numEdges=0,curEdge = 0,looking = 1,edgeValCount = 0,i=0,looped = 0,choosing = 1,event,noloop=0,cancel=0, val;
144
short protect = 0, dist= 50;
145
short mvalo[2] = {0,0}, mval[2];
147
SetBlenderCursor(BC_VLOOPCURSOR);
148
for(search=em->edges.first;search;search=search->next)
151
/* start with v1 and go in one direction. */
153
getmouseco_areawin(mval);
154
if (mval[0] != mvalo[0] || mval[1] != mvalo[1]) {
160
nearest = findnearestedge(&dist); // returns actual distance in dist
162
scrarea_do_windraw(curarea); // after findnearestedge, backbuf!
164
if (nearest && edgeFaces(nearest)==2) {
165
for(search = em->edges.first;search;search=search->next)
168
compEdge = startEdge = nearest;
175
if(protect++ > numEdges) break;
176
if(edgeFaces(compEdge) != 2) break;
177
/*Find Edges that have v1*/
179
EdgeVal[0] = EdgeVal[1] = EdgeVal[2] = NULL;
181
for(valSearch = em->edges.first;valSearch;valSearch = valSearch->next){
182
if(valSearch->v1 == v1 || valSearch->v2 == v1){
183
if(valSearch != compEdge){
184
if((valSearch->v1->h == 0) && (valSearch->v2->h == 0)){
185
if(edgeFaces(valSearch) == 2){
187
EdgeVal[edgeValCount] = valSearch;
192
if(edgeValCount == 3)break;
194
/* Check that there was a valance of 4*/
195
if(edgeValCount != 2){
201
/* There were 3 edges, so find the one that does not share the previous edge */
203
if(sharesFace(compEdge,EdgeVal[i]) == 0){
204
/* We went all the way around the loop */
205
if(EdgeVal[i] == nearest){
211
/* we are still in the loop, so add the next edge*/
214
compEdge = EdgeVal[i];
215
if(compEdge->v1 == v1)
227
while(looking/* && !looped*/){
228
if(protect++ > numEdges) break;
229
if(edgeFaces(compEdge) != 2) break;
230
/*Find Edges that have v1*/
232
EdgeVal[0] = EdgeVal[1] = EdgeVal[2] = NULL;
234
for(valSearch = em->edges.first;valSearch;valSearch = valSearch->next){
235
if(valSearch->v1 == v2 || valSearch->v2 == v2){
236
if(valSearch != compEdge){
237
if((valSearch->v1->h == 0) && (valSearch->v2->h == 0)){
238
if(edgeFaces(valSearch) == 2){
240
EdgeVal[edgeValCount] = valSearch;
245
if(edgeValCount == 3)break;
247
/* Check that there was a valance of 4*/
248
if(edgeValCount != 2){
254
/* There were 3 edges, so find the one that does not share the previous edge */
256
if(sharesFace(compEdge,EdgeVal[i]) == 0){
257
/* We went all the way around the loop */
258
if(EdgeVal[i] == nearest){
264
/* we are still in the loop, so add the next edge*/
267
compEdge = EdgeVal[i];
268
if(compEdge->v1 == v2)
277
/* set up for opengl drawing in the 3d window */
280
mymultmatrix(G.obedit->obmat);
281
glColor3ub(0, 255, 255);
282
for(search = em->edges.first;search;search= search->next){
285
glVertex3f(search->v1->co[0],search->v1->co[1],search->v1->co[2]);
286
glVertex3f(search->v2->co[0],search->v2->co[1],search->v2->co[2]);
294
screen_swapbuffers();
296
/* backbuffer refresh for non-apples (no aux) */
298
if(G.vd->drawtype>OB_WIRE && (G.vd->flag & V3D_ZBUF_SELECT)) {
303
else PIL_sleep_ms(10); // idle
308
event= extern_qread(&val);
309
if(val && ((event==LEFTMOUSE || event==RETKEY) || event == MIDDLEMOUSE))
316
if(val && (event==ESCKEY || event==RIGHTMOUSE ))
322
if(val && (event==BKEY && G.qual==LR_ALTKEY ))
325
SetBlenderCursor(SYSCURSOR);
326
loopoperations(LOOP_SELECT);
332
/* If this is a unmodified select, clear the selection */
334
/* XXX note that !1 is 0, so it not only clears bit 1 (ton) */
335
if(!(G.qual & LR_SHIFTKEY) && !(G.qual & LR_ALTKEY)){
336
for(search = em->edges.first;search;search= search->next){
340
EM_clear_flag_all(SELECT); /* XXX probably that's sufficient */
342
/* Alt was not pressed, so add to the selection */
343
if(!(G.qual & LR_ALTKEY)){
344
for(search = em->edges.first;search;search= search->next){
351
/* XXX this will correctly flush */
353
/* alt was pressed, so subtract from the selection */
356
/* XXX this doesnt flush correct in face select mode */
357
for(search = em->edges.first;search;search= search->next){
361
EM_select_edge(search, 0); // the call to deselect edge
367
EM_select_flush(); // flushes vertex -> edge -> face selection
371
BIF_undo_push("Select Vertex Loop");
374
addqueue(curarea->win, REDRAW, 1);
375
SetBlenderCursor(SYSCURSOR);
379
/* *********** END LOOP SELECT ********** */
383
/* ***************** TRAIL ************************
385
Read a trail of mouse coords and return them as an array of CutCurve structs
386
len returns number of mouse coords read before commiting with RETKEY
387
It is up to the caller to free the block when done with it,
389
XXX Is only used here, so local inside this file (ton)
392
#define TRAIL_POLYLINE 1 /* For future use, They don't do anything yet */
393
#define TRAIL_FREEHAND 2
394
#define TRAIL_MIXED 3 /* (1|2) */
396
#define TRAIL_MIDPOINTS 8
398
typedef struct CutCurve {
403
static CutCurve *get_mouse_trail(int *len, char mode){
405
CutCurve *curve,*temp;
406
short event, val, ldown=0, restart=0, rubberband=0;
407
short mval[2], lockaxis=0, lockx=0, locky=0, lastx=0, lasty=0;
408
int i=0, j, blocks=1, lasti=0;
411
curve=(CutCurve *)MEM_callocN(1024*sizeof(CutCurve), "MouseTrail");
414
printf("failed to allocate memory in get_mouse_trail()\n");
417
mywinset(curarea->win);
418
glDrawBuffer(GL_FRONT);
420
headerprint("LMB to draw, Enter to finish, ESC to abort.");
424
glColor3ub(200, 200, 0);
428
event=extern_qread(&val); /* Enter or RMB indicates finish */
430
if(event==RETKEY || event==PADENTER) break;
433
if( event==ESCKEY || event==RIGHTMOUSE ) {
434
if (curve) MEM_freeN(curve);
437
glDrawBuffer(GL_BACK);
442
if (rubberband) { /* rubberband mode, undraw last rubberband */
444
sdrawXORline(curve[i-1].x, curve[i-1].y,mval[0], mval[1]);
450
getmouseco_areawin(mval);
452
if (lockaxis==1) mval[1]=locky;
453
if (lockaxis==2) mval[0]=lockx;
455
if ( ((i==0) || (mval[0]!=curve[i-1].x) || (mval[1]!=curve[i-1].y))
456
&& (get_mbut() & L_MOUSE) ){ /* record changes only, if LMB down */
458
lastx=curve[i].x=mval[0];
459
lasty=curve[i].y=mval[1];
467
for(j=1;j<i;j++) sdrawXORline(curve[j-1].x, curve[j-1].y, curve[j].x, curve[j].y);
468
if (rubberband) sdrawXORline(curve[j].x, curve[j].y, mval[0], mval[1]);
477
if ((event==MIDDLEMOUSE)&&(get_mbut()&M_MOUSE)&&(i)){/*MMB Down*/
478
/*determine which axis to lock to, or clear if locked */
479
if (lockaxis) lockaxis=0;
480
else if (abs(curve[i-1].x-mval[0]) > abs(curve[i-1].y-mval[1])) lockaxis=1;
489
if ((i>1)&&(i!=lasti)) { /*Draw recorded part of curve */
490
sdrawline(curve[i-2].x, curve[i-2].y, curve[i-1].x, curve[i-1].y);
494
if ((i==lasti)&&(i>0)) { /*Draw rubberband */
496
sdrawXORline(curve[i-1].x, curve[i-1].y,mval[0], mval[1]);
503
if (i>=blocks*1024) { /* reallocate data if out of room */
505
curve=(CutCurve *)MEM_callocN((blocks+1)*1024*sizeof(CutCurve), "MouseTrail");
507
printf("failed to re-allocate memory in get_mouse_trail()\n");
510
memcpy(curve, temp, blocks*1024*sizeof(CutCurve));
517
glDrawBuffer(GL_BACK);
528
/* ******************************************************************** */
529
/* Knife Subdivide Tool. Subdivides edges intersected by a mouse trail
532
Currently mapped to KKey when in MeshEdit mode.
534
Hit Shift K, Select Centers or Exact
535
Hold LMB down to draw path, hit RETKEY.
536
ESC cancels as expected.
538
Contributed by Robert Wenzlaff (Det. Thorn).
542
short seg_intersect(struct EditEdge * e, CutCurve *c, int len);
544
void KnifeSubdivide(char mode)
546
EditMesh *em = G.editMesh;
547
int oldcursor, len=0;
553
if (G.obedit==0) return;
555
if (EM_nvertices_selected() < 2) {
556
error("No edges are selected to operate on");
560
if (mode==KNIFE_PROMPT) {
561
short val= pupmenu("Cut Type %t|Exact Line%x1|Midpoints%x2");
563
mode= val; // warning, mode is char, pupmenu returns -1 with ESC
566
calc_meshverts_ext(); /*Update screen coords for current window */
568
/* Set a knife cursor here */
569
oldcursor=get_cursor();
571
win=winlay_get_active_window();
573
SetBlenderCursor(BC_KNIFECURSOR);
575
curve=get_mouse_trail(&len, TRAIL_MIXED);
577
if (curve && len && mode){
578
eed= em->edges.first;
580
if( eed->f & SELECT ){
581
isect=seg_intersect(eed, curve, len);
582
if (isect) eed->f2= 1;
585
//printf("isect=%i\n", isect);
594
if (mode==1) subdivideflag(1, 0, B_KNIFE|B_PERCENTSUBD);
595
else if (mode==2) subdivideflag(1, 0, B_KNIFE);
604
/* Return to old cursor and flags...*/
606
addqueue(curarea->win, REDRAW, 0);
607
window_set_cursor(win, oldcursor);
608
if (curve) MEM_freeN(curve);
610
BIF_undo_push("Knife");
613
/* seg_intersect() Determines if and where a mouse trail intersects an EditEdge */
615
short seg_intersect(EditEdge *e, CutCurve *c, int len){
616
#define MAXSLOPE 100000
618
float x11, y11, x12=0, y12=0, x2max, x2min, y2max;
619
float y2min, dist, lastdist=0, xdiff2, xdiff1;
620
float m1, b1, m2, b2, x21, x22, y21, y22, xi;
621
float yi, x1min, x1max, y1max, y1min, perc=0;
625
/* Get screen coords of verts (v->xs and v->ys clip if off screen */
626
VECCOPY(co, e->v1->co);
628
Mat4MulVec4fl(G.obedit->obmat, co);
629
project_float(co, scr);
633
VECCOPY(co, e->v2->co);
635
Mat4MulVec4fl(G.obedit->obmat, co);
636
project_float(co, scr);
643
b2= ((x22*y21)-(x21*y22))/xdiff2;
646
m2=MAXSLOPE; /* Verticle slope */
649
for (i=0; i<len; i++){
661
/* Perp. Distance from point to line */
662
if (m2!=MAXSLOPE) dist=(y12-m2*x12-b2);/* /sqrt(m2*m2+1); Only looking for */
663
/* change in sign. Skip extra math */
666
if (i==0) lastdist=dist;
668
/* if dist changes sign, and intersect point in edge's Bound Box*/
669
if ((lastdist*dist)<=0){
670
xdiff1=(x12-x11); /* Equation of line between last 2 points */
673
b1= ((x12*y11)-(x11*y12))/xdiff1;
679
x2max=MAX2(x21,x22)+0.001; /* prevent missed edges */
680
x2min=MIN2(x21,x22)-0.001; /* due to round off error */
681
y2max=MAX2(y21,y22)+0.001;
682
y2min=MIN2(y21,y22)-0.001;
684
/* Found an intersect, calc intersect point */
685
if (m1==m2){ /* co-incident lines */
686
/* cut at 50% of overlap area*/
687
x1max=MAX2(x11, x12);
688
x1min=MIN2(x11, x12);
689
xi= (MIN2(x2max,x1max)+MAX2(x2min,x1min))/2.0;
691
y1max=MAX2(y11, y12);
692
y1min=MIN2(y11, y12);
693
yi= (MIN2(y2max,y1max)+MAX2(y2min,y1min))/2.0;
695
else if (m2==MAXSLOPE){
699
else if (m1==MAXSLOPE){
705
yi=(b1*m2-m1*b2)/(m2-m1);
708
/* Intersect inside bounding box of edge?*/
709
if ((xi>=x2min)&&(xi<=x2max)&&(yi<=y2max)&&(yi>=y2min)){
710
if ((m2<=1.0)&&(m2>=-1.0)) perc = (xi-x21)/(x22-x21);
711
else perc=(yi-y21)/(y22-y21); /*lower slope more accurate*/
712
isect=32768.0*(perc+0.0000153); /* Percentage in 1/32768ths */
721
/* ******************** LOOP ******************************************* */
723
/* XXX: this loop function is totally out of control!
724
can be half the code, and using structured functions (ton) */
727
functionality: various loop functions
728
parameters: mode tells the function what it should do with the loop:
730
LOOP_CUT = cut in half
733
void loopoperations(char mode)
735
EditMesh *em = G.editMesh;
736
EditVert* look = NULL;
737
EditEdge *start, *eed, *opposite,*currente, *oldstart;
738
EditEdge **tagged = NULL,**taggedsrch = NULL,*close;
739
EditFace *efa,**percentfacesloop = NULL, *currentvl, *formervl;
740
short lastface=0, foundedge=0, c=0, tri=0, side=1, totface=0, searching=1, event=0, noface=1;
741
short skip,nextpos,percentfaces, dist=50;
743
int i=0,ect=0,j=0,k=0,cut,smooth,timesthrough=0,inset = 0;
745
float percentcut, outcut;
749
if ((G.obedit==0) || (em->faces.first==0)) return;
751
SetBlenderCursor(BC_VLOOPCURSOR);
754
for(eed=em->edges.first; eed; eed=eed->next) eed->f2= 0;
755
for(efa= em->faces.first; efa; efa=efa->next) efa->f1= 0;
762
/* reset variables */
763
start=eed=opposite=currente=0;
764
efa=currentvl=formervl=0;
766
lastface=foundedge=c=tri=totface=0;
768
//start=findnearestvisibleedge();
770
start= findnearestedge(&dist);
772
/* used flags in the code:
773
vertex->f & 2: in findnearestvisibleedge
774
edge->f2 : subdiv codes
775
efa->f1 : subdiv codes
778
/* If the edge doesn't belong to a face, it's not a valid starting edge */
779
/* and only accept starting edge if it is part of at least one visible face */
784
/* since this edge is on the face, check if the face is hidden */
786
if(efa->e1->f2 & 16){
790
else if(efa->e2->f2 & 16){
794
else if(efa->e3->f2 & 16){
798
else if(efa->e4 && (efa->e4->f2 & 16)){
807
/* Did we find anything that is selectable? */
808
if(start && !noface && (oldstart==NULL || start!=oldstart)){
810
/* If we stay in the neighbourhood of this edge, we don't have to recalculate the loop everytime*/
814
for(eed=em->edges.first; eed; eed=eed->next){
815
eed->f2 &= ~(2|4|8|32|64);
816
eed->v1->f &= ~(2|8|16); // xxxx
817
eed->v2->f &= ~(2|8|16);
820
for(efa= em->faces.first; efa; efa=efa->next){
825
/* Tag the starting edge */
826
start->f2 |= (2|4|8|64);
827
start->v1->f |= 2; /* xxxx */
832
/*-----Limit the Search----- */
833
while(!lastface && c<totface+1){
835
/*----------Get Loop------------------------*/
836
tri=foundedge=lastface=0;
837
efa= em->faces.first;
838
while(efa && !foundedge && !tri){
840
if(!(efa->v4)){ /* Exception for triangular faces */
842
if((efa->e1->f2 | efa->e2->f2 | efa->e3->f2) & 2){
846
if(side==1) efa->f1 |= 4;
852
if((efa->e1->f2 | efa->e2->f2 | efa->e3->f2 | efa->e4->f2) & 2){
854
if(c==0){ /* just pick a face, doesn't matter wich side of the edge we go to */
857
if(!(efa->e1->v1->f & 2) && !(efa->e1->v2->f & 2)){ // xxxxx
863
else if(!(efa->e2->v1->f & 2) && !(efa->e2->v2->f & 2)){ // xxxx
869
else if(!(efa->e3->v1->f & 2) && !(efa->e3->v2->f & 2)){
875
else if(!(efa->e4->v1->f & 2) && !(efa->e4->v2->f & 2)){
886
/* mark this side of the edge so we know in which direction we went */
887
if(side==1) efa->f1 |= 4;
892
if(efa!=formervl){ /* prevent going backwards in the loop */
894
if(!(efa->e1->v1->f & 2) && !(efa->e1->v2->f & 2)){
900
else if(!(efa->e2->v1->f & 2) && !(efa->e2->v2->f & 2)){
906
else if(!(efa->e3->v1->f & 2) && !(efa->e3->v2->f & 2)){
912
else if(!(efa->e4->v1->f & 2) && !(efa->e4->v2->f & 2)){
926
/*----------END Get Loop------------------------*/
929
/*----------Decisions-----------------------------*/
931
/* mark the edge and face as done */
935
if(opposite->f2 & 4) lastface=1; /* found the starting edge! close loop */
937
/* un-set the testflags */
939
currente->v1->f &= ~2; // xxxx
940
currente->v2->f &= ~2;
942
/* set the opposite edge to be the current edge */
945
/* set the current face to be the FORMER face (to prevent going backwards in the loop) */
948
/* set the testflags */
950
currente->v1->f |= 2; // xxxx
951
currente->v2->f |= 2;
956
/* un-set the testflags */
958
currente->v1->f &= ~2; // xxxx
959
currente->v2->f &= ~2;
961
/* mark the edge and face as done */
967
/* is the the first time we've ran out of possible faces?
968
* try to start from the beginning but in the opposite direction go as far as possible
974
currente->v1->f |= 2; // xxxx
975
currente->v2->f |= 2;
981
/*----------END Decisions-----------------------------*/
984
/*-----END Limit the Search----- */
987
/*------------- Preview lines--------------- */
989
/* uses callback mechanism to draw it all in current area */
990
scrarea_do_windraw(curarea);
992
/* set window matrix to perspective, default an area returns with buttons transform */
994
/* make a copy, for safety */
996
/* multiply with the object transformation */
997
mymultmatrix(G.obedit->obmat);
999
glColor3ub(255, 255, 0);
1001
if(mode==LOOP_SELECT){
1002
efa= em->faces.first;
1006
if(!(efa->e1->f2 & 8)){
1008
glVertex3fv(efa->e1->v1->co);
1009
glVertex3fv(efa->e1->v2->co);
1013
if(!(efa->e2->f2 & 8)){
1015
glVertex3fv(efa->e2->v1->co);
1016
glVertex3fv(efa->e2->v2->co);
1020
if(!(efa->e3->f2 & 8)){
1022
glVertex3fv(efa->e3->v1->co);
1023
glVertex3fv(efa->e3->v2->co);
1028
if(!(efa->e4->f2 & 8)){
1030
glVertex3fv(efa->e4->v1->co);
1031
glVertex3fv(efa->e4->v2->co);
1041
efa= em->faces.first;
1047
efa->v1->f &= ~8; // xxx
1050
if(efa->v4)efa->v4->f &= ~8;
1052
if(efa->e1->f2 & 8){
1053
cen[a][0]= (efa->e1->v1->co[0] + efa->e1->v2->co[0])/2.0;
1054
cen[a][1]= (efa->e1->v1->co[1] + efa->e1->v2->co[1])/2.0;
1055
cen[a][2]= (efa->e1->v1->co[2] + efa->e1->v2->co[2])/2.0;
1057
efa->e1->v1->f |= 8; // xxx
1058
efa->e1->v2->f |= 8;
1062
if((efa->e2->f2 & 8) && a!=2){
1063
cen[a][0]= (efa->e2->v1->co[0] + efa->e2->v2->co[0])/2.0;
1064
cen[a][1]= (efa->e2->v1->co[1] + efa->e2->v2->co[1])/2.0;
1065
cen[a][2]= (efa->e2->v1->co[2] + efa->e2->v2->co[2])/2.0;
1067
efa->e2->v1->f |= 8; // xxx
1068
efa->e2->v2->f |= 8;
1072
if((efa->e3->f2 & 8) && a!=2){
1073
cen[a][0]= (efa->e3->v1->co[0] + efa->e3->v2->co[0])/2.0;
1074
cen[a][1]= (efa->e3->v1->co[1] + efa->e3->v2->co[1])/2.0;
1075
cen[a][2]= (efa->e3->v1->co[2] + efa->e3->v2->co[2])/2.0;
1077
efa->e3->v1->f |= 8; // xxx
1078
efa->e3->v2->f |= 8;
1084
if((efa->e4->f2 & 8) && a!=2){
1085
cen[a][0]= (efa->e4->v1->co[0] + efa->e4->v2->co[0])/2.0;
1086
cen[a][1]= (efa->e4->v1->co[1] + efa->e4->v2->co[1])/2.0;
1087
cen[a][2]= (efa->e4->v1->co[2] + efa->e4->v2->co[2])/2.0;
1089
efa->e4->v1->f |= 8; // xxx
1090
efa->e4->v2->f |= 8;
1095
else{ /* if it's a triangular face, set the remaining vertex as the cutcurve coordinate */
1096
if(!(efa->v1->f & 8) && efa->v1->h==0){ // xxx
1097
cen[a][0]= efa->v1->co[0];
1098
cen[a][1]= efa->v1->co[1];
1099
cen[a][2]= efa->v1->co[2];
1102
else if(!(efa->v2->f & 8) && efa->v2->h==0){
1103
cen[a][0]= efa->v2->co[0];
1104
cen[a][1]= efa->v2->co[1];
1105
cen[a][2]= efa->v2->co[2];
1108
else if(!(efa->v3->f & 8) && efa->v3->h==0){
1109
cen[a][0]= efa->v3->co[0];
1110
cen[a][1]= efa->v3->co[1];
1111
cen[a][2]= efa->v3->co[2];
1119
glVertex3fv(cen[0]);
1120
glVertex3fv(cen[1]);
1128
eed=em->edges.first;
1132
glColor3ub(200, 255, 200);
1133
glVertex3fv(eed->v1->co);
1134
glVertex3fv(eed->v2->co);
1143
/* restore matrix transform */
1146
headerprint("LMB to confirm, RMB to cancel");
1148
/* this also verifies other area/windows for clean swap */
1149
screen_swapbuffers();
1151
/* backbuffer refresh for non-apples (no aux) */
1153
if(G.vd->drawtype>OB_WIRE && (G.vd->flag & V3D_ZBUF_SELECT)) {
1158
/*--------- END Preview Lines------------*/
1160
}/*if(start!=NULL){ */
1161
else PIL_sleep_ms(10); // idle
1164
unsigned short val=0;
1165
event= extern_qread(&val); /* extern_qread stores important events for the mainloop to handle */
1167
/* val==0 on key-release event */
1168
if(val && (event==ESCKEY || event==RIGHTMOUSE || event==LEFTMOUSE || event==RETKEY || event == MIDDLEMOUSE)){
1173
}/*while(event!=ESCKEY && event!=RIGHTMOUSE && event!=LEFTMOUSE && event!=RETKEY){*/
1175
/*----------Select Loop------------*/
1176
if(mode==LOOP_SELECT && start!=NULL && ((event==LEFTMOUSE || event==RETKEY) || event == MIDDLEMOUSE || event == BKEY)){
1178
/* If this is a unmodified select, clear the selection */
1179
if(!(G.qual & LR_SHIFTKEY) && !(G.qual & LR_ALTKEY)){
1180
for(efa= em->faces.first;efa;efa=efa->next){
1181
EM_select_face(efa, 0); // and this is correct deselect face
1184
/* Alt was not pressed, so add to the selection */
1185
if(!(G.qual & LR_ALTKEY)){
1186
for(efa= em->faces.first;efa;efa=efa->next){
1188
EM_select_face(efa, 1); // and this is correct select face
1192
/* alt was pressed, so subtract from the selection */
1195
for(efa= em->faces.first;efa;efa=efa->next){
1197
EM_select_face(efa, 0); // this is correct deselect face
1203
/*----------END Select Loop------------*/
1205
/*----------Cut Loop---------------*/
1206
if(mode==LOOP_CUT && start!=NULL && (event==LEFTMOUSE || event==RETKEY)){
1208
/* count the number of edges in the loop */
1209
for(eed=em->edges.first; eed; eed = eed->next){
1214
tagged = MEM_mallocN(ect*sizeof(EditEdge*), "tagged");
1215
taggedsrch = MEM_mallocN(ect*sizeof(EditEdge*), "taggedsrch");
1219
taggedsrch[i] = NULL;
1222
for(eed=em->edges.first; eed; eed = eed->next){
1226
eed->v1->f |= SELECT;
1227
eed->v2->f |= SELECT;
1235
taggedsrch[0] = tagged[0];
1237
while(timesthrough < 2)
1240
while(i < ect){/*Look at the members of the search array to line up cuts*/
1241
if(taggedsrch[i]==NULL)break;
1242
for(j=0;j<ect;j++){ /*Look through the list of tagged verts for connected edges*/
1244
if(taggedsrch[i]->f2 & 32) /*If this edgee is marked as flipped, use vert 2*/
1245
look = taggedsrch[i]->v2;
1246
else /*else use vert 1*/
1247
look = taggedsrch[i]->v1;
1249
if(taggedsrch[i] == tagged[j])
1250
continue; /*If we are looking at the same edge, skip it*/
1253
for(k=0;k<ect;k++) {
1254
if(taggedsrch[k] == NULL) /*go to empty part of search list without finding*/
1256
if(tagged[j] == taggedsrch[k]){ /*We found a match already in the list*/
1264
if(findedgelist(look,tagged[j]->v2)){
1265
while(nextpos < ect){ /*Find the first open spot in the search array*/
1266
if(taggedsrch[nextpos] == NULL){
1267
taggedsrch[nextpos] = tagged[j]; /*put tagged[j] in it*/
1268
taggedsrch[nextpos]->f2 |= 32;
1275
} /* End else if connected to vert 2*/
1276
else if(findedgelist(look,tagged[j]->v1)){ /*If our vert is connected to vert 1 */
1277
while(nextpos < ect){ /*Find the first open spot in the search array */
1278
if(taggedsrch[nextpos] == NULL){
1279
taggedsrch[nextpos] = tagged[j]; /*put tagged[j] in it*/
1292
}/* End Outer For (j)*/
1294
} /* End while(j<ect)*/
1296
} /*end while timesthrough */
1304
/* Count the Number of Faces in the selected loop*/
1306
for(efa= em->faces.first; efa ;efa=efa->next){
1313
/* create a dynamic array for those face pointers */
1314
percentfacesloop = MEM_mallocN(percentfaces*sizeof(EditFace*), "percentage");
1316
/* put those faces in the array */
1318
for(efa= em->faces.first; efa ;efa=efa->next){
1321
percentfacesloop[i] = efa;
1328
/* For the % calculation */
1330
float labda, rc[2], len, slen=0.0;
1331
float v1[2], v2[2], v3[2];
1333
/*------------- Percent Cut Preview Lines--------------- */
1334
scrarea_do_windraw(curarea);
1337
mymultmatrix(G.obedit->obmat);
1338
glColor3ub(0, 255, 255);
1340
/*Put the preview lines where they should be for the percentage selected.*/
1342
for(i=0;i<percentfaces;i++){
1343
efa = percentfacesloop[i];
1344
for(eed = em->edges.first; eed; eed=eed->next){
1345
if(eed->f2 & 64){ /* color the starting edge */
1348
glColor3ub(200, 255, 200);
1349
glVertex3fv(eed->v1->co);
1350
glVertex3fv(eed->v2->co);
1356
glColor3ub(255,0,255);
1359
glVertex3fv(eed->v2->co);
1361
glVertex3fv(eed->v1->co);
1365
/*Get Starting Edge Length*/
1366
slen = sqrt((eed->v1->co[0]-eed->v2->co[0])*(eed->v1->co[0]-eed->v2->co[0])+
1367
(eed->v1->co[1]-eed->v2->co[1])*(eed->v1->co[1]-eed->v2->co[1])+
1368
(eed->v1->co[2]-eed->v2->co[2])*(eed->v1->co[2]-eed->v2->co[2]));
1373
glColor3ub(0,255,255);
1379
efa->v1->f &= ~8; // xxx
1382
if(efa->v4)efa->v4->f &= ~8;
1384
if(efa->e1->f2 & 8){
1386
if(efa->e1->f2 & 32)
1390
cen[a][0]= efa->e1->v1->co[0] - ((efa->e1->v1->co[0] - efa->e1->v2->co[0]) * (pct));
1391
cen[a][1]= efa->e1->v1->co[1] - ((efa->e1->v1->co[1] - efa->e1->v2->co[1]) * (pct));
1392
cen[a][2]= efa->e1->v1->co[2] - ((efa->e1->v1->co[2] - efa->e1->v2->co[2]) * (pct));
1393
efa->e1->v1->f |= 8; // xxx
1394
efa->e1->v2->f |= 8;
1397
if((efa->e2->f2 & 8) && a!=2)
1400
if(efa->e2->f2 & 32)
1404
cen[a][0]= efa->e2->v1->co[0] - ((efa->e2->v1->co[0] - efa->e2->v2->co[0]) * (pct));
1405
cen[a][1]= efa->e2->v1->co[1] - ((efa->e2->v1->co[1] - efa->e2->v2->co[1]) * (pct));
1406
cen[a][2]= efa->e2->v1->co[2] - ((efa->e2->v1->co[2] - efa->e2->v2->co[2]) * (pct));
1408
efa->e2->v1->f |= 8; // xxx
1409
efa->e2->v2->f |= 8;
1413
if((efa->e3->f2 & 8) && a!=2){
1415
if(efa->e3->f2 & 32)
1419
cen[a][0]= efa->e3->v1->co[0] - ((efa->e3->v1->co[0] - efa->e3->v2->co[0]) * (pct));
1420
cen[a][1]= efa->e3->v1->co[1] - ((efa->e3->v1->co[1] - efa->e3->v2->co[1]) * (pct));
1421
cen[a][2]= efa->e3->v1->co[2] - ((efa->e3->v1->co[2] - efa->e3->v2->co[2]) * (pct));
1423
efa->e3->v1->f |= 8; // xxx
1424
efa->e3->v2->f |= 8;
1430
if((efa->e4->f2 & 8) && a!=2){
1432
if(efa->e4->f2 & 32)
1436
cen[a][0]= efa->e4->v1->co[0] - ((efa->e4->v1->co[0] - efa->e4->v2->co[0]) * (pct));
1437
cen[a][1]= efa->e4->v1->co[1] - ((efa->e4->v1->co[1] - efa->e4->v2->co[1]) * (pct));
1438
cen[a][2]= efa->e4->v1->co[2] - ((efa->e4->v1->co[2] - efa->e4->v2->co[2]) * (pct));
1440
efa->e4->v1->f |= 8; // xxx
1441
efa->e4->v2->f |= 8;
1446
else { /* if it's a triangular face, set the remaining vertex as the cutcurve coordinate */
1447
if(!(efa->v1->f & 8) && efa->v1->h==0){ // xxx
1448
cen[a][0]= efa->v1->co[0];
1449
cen[a][1]= efa->v1->co[1];
1450
cen[a][2]= efa->v1->co[2];
1453
else if(!(efa->v2->f & 8) && efa->v2->h==0){ // xxx
1454
cen[a][0]= efa->v2->co[0];
1455
cen[a][1]= efa->v2->co[1];
1456
cen[a][2]= efa->v2->co[2];
1459
else if(!(efa->v3->f & 8) && efa->v3->h==0){ // xxx
1460
cen[a][0]= efa->v3->co[0];
1461
cen[a][1]= efa->v3->co[1];
1462
cen[a][2]= efa->v3->co[2];
1470
glVertex3fv(cen[0]);
1471
glVertex3fv(cen[1]);
1476
}/* end preview line drawing */
1478
glColor3ub(0,128,255);
1484
efa->v1->f &= ~8; // xxx
1487
if(efa->v4)efa->v4->f &= ~8;
1489
if(efa->e1->f2 & 8){
1492
nlen = sqrt((efa->e1->v1->co[0] - efa->e1->v2->co[0])*(efa->e1->v1->co[0] - efa->e1->v2->co[0])+
1493
(efa->e1->v1->co[1] - efa->e1->v2->co[1])*(efa->e1->v1->co[1] - efa->e1->v2->co[1])+
1494
(efa->e1->v1->co[2] - efa->e1->v2->co[2])*(efa->e1->v1->co[2] - efa->e1->v2->co[2]));
1495
npct = (percentcut*slen)/nlen;
1496
if(npct >= 1) npct = 1;
1497
if(efa->e1->f2 & 32) npct = 1-npct;
1499
cen[a][0]= efa->e1->v1->co[0] - ((efa->e1->v1->co[0] - efa->e1->v2->co[0]) * (npct));
1500
cen[a][1]= efa->e1->v1->co[1] - ((efa->e1->v1->co[1] - efa->e1->v2->co[1]) * (npct));
1501
cen[a][2]= efa->e1->v1->co[2] - ((efa->e1->v1->co[2] - efa->e1->v2->co[2]) * (npct));
1503
efa->e1->f1 = 32768*(npct);
1504
efa->e1->v1->f |= 8; // xxx
1505
efa->e1->v2->f |= 8;
1508
if((efa->e2->f2 & 8) && a!=2)
1512
nlen = sqrt((efa->e2->v1->co[0] - efa->e2->v2->co[0])*(efa->e2->v1->co[0] - efa->e2->v2->co[0])+
1513
(efa->e2->v1->co[1] - efa->e2->v2->co[1])*(efa->e2->v1->co[1] - efa->e2->v2->co[1])+
1514
(efa->e2->v1->co[2] - efa->e2->v2->co[2])*(efa->e2->v1->co[2] - efa->e2->v2->co[2]));
1515
npct = (percentcut*slen)/nlen;
1516
if(npct >= 1) npct = 1;
1517
if(efa->e2->f2 & 32) npct = 1-npct;
1519
cen[a][0]= efa->e2->v1->co[0] - ((efa->e2->v1->co[0] - efa->e2->v2->co[0]) * (npct));
1520
cen[a][1]= efa->e2->v1->co[1] - ((efa->e2->v1->co[1] - efa->e2->v2->co[1]) * (npct));
1521
cen[a][2]= efa->e2->v1->co[2] - ((efa->e2->v1->co[2] - efa->e2->v2->co[2]) * (npct));
1523
efa->e2->f1 = 32768*(npct);
1524
efa->e2->v1->f |= 8; // xxx
1525
efa->e2->v2->f |= 8;
1528
if((efa->e3->f2 & 8) && a!=2){
1531
nlen = sqrt((efa->e3->v1->co[0] - efa->e3->v2->co[0])*(efa->e3->v1->co[0] - efa->e3->v2->co[0])+
1532
(efa->e3->v1->co[1] - efa->e3->v2->co[1])*(efa->e3->v1->co[1] - efa->e3->v2->co[1])+
1533
(efa->e3->v1->co[2] - efa->e3->v2->co[2])*(efa->e3->v1->co[2] - efa->e3->v2->co[2]));
1534
npct = (percentcut*slen)/nlen;
1535
if(npct >= 1) npct = 1;
1536
if(efa->e3->f2 & 32) npct = 1-npct;
1538
cen[a][0]= efa->e3->v1->co[0] - ((efa->e3->v1->co[0] - efa->e3->v2->co[0]) * (npct));
1539
cen[a][1]= efa->e3->v1->co[1] - ((efa->e3->v1->co[1] - efa->e3->v2->co[1]) * (npct));
1540
cen[a][2]= efa->e3->v1->co[2] - ((efa->e3->v1->co[2] - efa->e3->v2->co[2]) * (npct));
1542
efa->e3->f1 = 32768*(npct);
1543
efa->e3->v1->f |= 8; // xxx
1544
efa->e3->v2->f |= 8;
1549
if((efa->e4->f2 & 8) && a!=2){
1552
nlen = sqrt((efa->e4->v1->co[0] - efa->e4->v2->co[0])*(efa->e4->v1->co[0] - efa->e4->v2->co[0])+
1553
(efa->e4->v1->co[1] - efa->e4->v2->co[1])*(efa->e4->v1->co[1] - efa->e4->v2->co[1])+
1554
(efa->e4->v1->co[2] - efa->e4->v2->co[2])*(efa->e4->v1->co[2] - efa->e4->v2->co[2]));
1555
npct = (percentcut*slen)/nlen;
1556
if(npct >= 1) npct = 1;
1557
if(efa->e4->f2 & 32) npct = 1-npct;
1559
cen[a][0]= efa->e4->v1->co[0] - ((efa->e4->v1->co[0] - efa->e4->v2->co[0]) * (npct));
1560
cen[a][1]= efa->e4->v1->co[1] - ((efa->e4->v1->co[1] - efa->e4->v2->co[1]) * (npct));
1561
cen[a][2]= efa->e4->v1->co[2] - ((efa->e4->v1->co[2] - efa->e4->v2->co[2]) * (npct));
1563
efa->e4->f1 = 32768*(npct);
1564
efa->e4->v1->f |= 8; // xxx
1565
efa->e4->v2->f |= 8;
1569
else { /* if it's a triangular face, set the remaining vertex as the cutcurve coordinate */
1570
if(!(efa->v1->f & 8) && efa->v1->h==0){ // xxx
1571
cen[a][0]= efa->v1->co[0];
1572
cen[a][1]= efa->v1->co[1];
1573
cen[a][2]= efa->v1->co[2];
1576
else if(!(efa->v2->f & 8) && efa->v2->h==0){ // xxx
1577
cen[a][0]= efa->v2->co[0];
1578
cen[a][1]= efa->v2->co[1];
1579
cen[a][2]= efa->v2->co[2];
1582
else if(!(efa->v3->f & 8) && efa->v3->h==0){ // xxx
1583
cen[a][0]= efa->v3->co[0];
1584
cen[a][1]= efa->v3->co[1];
1585
cen[a][2]= efa->v3->co[2];
1593
glVertex3fv(cen[0]);
1594
glVertex3fv(cen[1]);
1601
/* restore matrix transform */
1605
/*--------- END Preview Lines------------*/
1608
unsigned short val=0;
1609
event= extern_qread(&val); /* extern_qread stores important events for the mainloop to handle */
1610
/* val==0 on key-release event */
1612
if(val && (event==SKEY))
1614
if(smooth)smooth = 0;
1618
if(val && (event==PKEY))
1624
if(val && (event==FKEY))
1627
for(ct = 0; ct < ect; ct++){
1628
if(tagged[ct]->f2 & 32)
1629
tagged[ct]->f2 &= ~32;
1631
tagged[ct]->f2 |= 32;
1635
if(val && (event == MIDDLEMOUSE))
1640
else if(val && (event==LEFTMOUSE || event==RETKEY))
1645
if(val && (event==ESCKEY || event==RIGHTMOUSE ))
1653
/* window coords, no clip with vertices f2 flags set (not used) */
1654
calc_meshverts_ext_f2();
1657
/* Determine the % on wich the loop should be cut */
1658
getmouseco_areawin(mval);
1659
v1[0]=(float)mval[0];
1660
v1[1]=(float)mval[1];
1662
v2[0]=(float)start->v1->xs;
1663
v2[1]=(float)start->v1->ys;
1665
v3[0]=(float)start->v2->xs;
1666
v3[1]=(float)start->v2->ys;
1670
len= rc[0]*rc[0]+ rc[1]*rc[1];
1672
labda= ( rc[0]*(v1[0]-v2[0]) + rc[1]*(v1[1]-v2[1]) )/len;
1675
if(labda<=0.0) labda=0.0;
1676
else if(labda>=1.0)labda=1.0;
1681
percentcut = 1.0-percentcut;
1687
if (G.qual & LR_SHIFTKEY){
1689
percentcut = (int)(percentcut*100.0)/100.0;
1691
else if (G.qual & LR_CTRLKEY)
1692
percentcut = (int)(percentcut*10.0)/10.0;
1694
outcut = (percentcut*100.0);
1696
/* Build the Header Line */
1699
sprintf(mesg,"Cut: %0.2f%% ",slen*percentcut);
1701
sprintf(mesg,"Cut: %0.2f%% ",outcut);
1705
sprintf(mesg,"%s| (f)lip side | (s)mooth on |",mesg);
1707
sprintf(mesg,"%s| (f)lip side | (s)mooth off |",mesg);
1710
sprintf(mesg,"%s (p)roportional on ",mesg);
1712
sprintf(mesg,"%s (p)roportional off",mesg);
1716
screen_swapbuffers();
1720
/* Now that we have selected a cut %, mark the edges for cutting. */
1723
for(eed = em->edges.first; eed; eed=eed->next){
1724
if(percentcut == 1.0)
1725
percentcut = 0.9999;
1726
else if(percentcut == 0.0)
1727
percentcut = 0.0001;
1729
if(eed->f2 & 32)/* Need to offset by a const. (0.5/32768) for consistant roundoff */
1730
eed->f1 = 32768*(1.0-percentcut - 0.0000153);
1732
eed->f1 = 32768*(percentcut + 0.0000153);
1736
/*-------------------------------------*/
1739
subdivideflag(8, 0, B_KNIFE | B_PERCENTSUBD | B_SMOOTH); /* B_KNIFE tells subdivide that edgeflags are already set */
1741
subdivideflag(8, 0, B_KNIFE | B_PERCENTSUBD); /* B_KNIFE tells subdivide that edgeflags are already set */
1743
for(eed = em->edges.first; eed; eed=eed->next){
1744
if(eed->v1->f & 16) eed->v1->f |= SELECT; //
1745
else eed->v1->f &= ~SELECT;
1747
if(eed->v2->f & 16) eed->v2->f |= SELECT;
1748
else eed->v2->f &= ~SELECT;
1750
/* proper edge select state, needed because subdivide still doesnt do it OK */
1751
if(eed->v1->f & eed->v2->f & SELECT) eed->f |= SELECT;
1752
else eed->f &= ~SELECT;
1756
/*----------END Cut Loop-----------------------------*/
1761
for(eed = em->edges.first; eed; eed=eed->next){
1762
eed->f2 &= ~(2|4|8|32|64);
1763
eed->v1->f &= ~(2|16); // xxx
1764
eed->v2->f &= ~(2|16);
1767
for(efa= em->faces.first; efa; efa=efa->next){
1770
/* proper face select state, needed because subdivide still doesnt do it OK */
1771
if( faceselectedAND(efa, SELECT) ) efa->f |= SELECT;
1772
else efa->f &= ~SELECT;
1775
// flushes vertex -> edge -> face selection
1783
MEM_freeN(taggedsrch);
1784
if(percentfacesloop)
1785
MEM_freeN(percentfacesloop);
1787
/* send event to redraw this window, does header too */
1788
SetBlenderCursor(SYSCURSOR);
1789
addqueue(curarea->win, REDRAW, 1);
1791
/* should have check for cancelled (ton) */
1792
if(mode==LOOP_CUT) BIF_undo_push("Face Loop Subdivide");
1793
else if(mode==LOOP_SELECT) BIF_undo_push("Select Face Loop");
1797
/* ****************************** END LOOPOPERATIONS ********************** */
1799
void LoopMenu(){ /* Called by KKey */
1803
ret=pupmenu("Loop/Cut Menu %t|Face Loop Select %x1|Face Loop Cut %x2|"
1804
"Knife (Exact) %x3|Knife (Midpoints)%x4|");
1808
loopoperations(LOOP_SELECT);
1811
loopoperations(LOOP_CUT);
1814
KnifeSubdivide(KNIFE_EXACT);
1817
KnifeSubdivide(KNIFE_MIDPOINT);