124
/* *********************** GESTURE AND LASSO ******************* */
126
/* helper also for borderselect */
127
static int edge_fully_inside_rect(rcti rect, short x1, short y1, short x2, short y2)
130
// check points in rect
131
if(rect.xmin<x1 && rect.xmax>x1 && rect.ymin<y1 && rect.ymax>y1)
132
if(rect.xmin<x2 && rect.xmax>x2 && rect.ymin<y2 && rect.ymax>y2) return 1;
138
static int edge_inside_rect(rcti rect, short x1, short y1, short x2, short y2)
142
// check points in rect
143
if(rect.xmin<x1 && rect.xmax>x1 && rect.ymin<y1 && rect.ymax>y1) return 1;
144
if(rect.xmin<x2 && rect.xmax>x2 && rect.ymin<y2 && rect.ymax>y2) return 1;
146
/* check points completely out rect */
147
if(x1<rect.xmin && x2<rect.xmin) return 0;
148
if(x1>rect.xmax && x2>rect.xmax) return 0;
149
if(y1<rect.ymin && y2<rect.ymin) return 0;
150
if(y1>rect.ymax && y2>rect.ymax) return 0;
152
// simple check lines intersecting.
153
d1= (y1-y2)*(x1- rect.xmin ) + (x2-x1)*(y1- rect.ymin );
154
d2= (y1-y2)*(x1- rect.xmin ) + (x2-x1)*(y1- rect.ymax );
155
d3= (y1-y2)*(x1- rect.xmax ) + (x2-x1)*(y1- rect.ymax );
156
d4= (y1-y2)*(x1- rect.xmax ) + (x2-x1)*(y1- rect.ymin );
158
if(d1<0 && d2<0 && d3<0 && d4<0) return 0;
159
if(d1>0 && d2>0 && d3>0 && d4>0) return 0;
165
#define MOVES_GESTURE 50
166
#define MOVES_LASSO 500
168
static int lasso_inside(short mcords[][2], short moves, short sx, short sy)
170
/* we do the angle rule, define that all added angles should be about zero or 2*PI */
171
float angletot=0.0, len, dot, ang, cross, fp1[2], fp2[2];
179
fp1[0]= (float)(p1[0]-sx);
180
fp1[1]= (float)(p1[1]-sy);
181
len= sqrt(fp1[0]*fp1[0] + fp1[1]*fp1[1]);
185
for(a=0; a<moves; a++) {
187
fp2[0]= (float)(p2[0]-sx);
188
fp2[1]= (float)(p2[1]-sy);
189
len= sqrt(fp2[0]*fp2[0] + fp2[1]*fp2[1]);
193
/* dot and angle and cross */
194
dot= fp1[0]*fp2[0] + fp1[1]*fp2[1];
195
ang= fabs(saacos(dot));
197
cross= (float)((p1[1]-p2[1])*(p1[0]-sx) + (p2[0]-p1[0])*(p1[1]-sy));
199
if(cross<0.0) angletot-= ang;
203
fp1[0]= fp2[0]; fp1[1]= fp2[1];
208
if( fabs(angletot) > 4.0 ) return 1;
212
/* edge version for lasso select. we assume boundbox check was done */
213
static int lasso_inside_edge(short mcords[][2], short moves, short *v1, short *v2)
217
// check points in lasso
218
if(lasso_inside(mcords, moves, v1[0], v1[1])) return 1;
219
if(lasso_inside(mcords, moves, v2[0], v2[1])) return 1;
221
/* no points in lasso, so we have to intersect with lasso edge */
223
if( IsectLL2Ds(mcords[0], mcords[moves-1], v1, v2) > 0) return 1;
224
for(a=0; a<moves-1; a++) {
225
if( IsectLL2Ds(mcords[a], mcords[a+1], v1, v2) > 0) return 1;
232
/* warning; lasso select with backbuffer-check draws in backbuf with persp(PERSP_WIN)
233
and returns with persp(PERSP_VIEW). After lasso select backbuf is not OK
235
static void do_lasso_select_objects(short mcords[][2], short moves, short select)
239
for(base= G.scene->base.first; base; base= base->next) {
240
if(base->lay & G.vd->lay) {
241
project_short(base->object->obmat[3], &base->sx);
242
if(lasso_inside(mcords, moves, base->sx, base->sy)) {
244
if(select) base->flag |= SELECT;
245
else base->flag &= ~SELECT;
246
base->object->flag= base->flag;
252
static void lasso_select_boundbox(rcti *rect, short mcords[][2], short moves)
256
rect->xmin= rect->xmax= mcords[0][0];
257
rect->ymin= rect->ymax= mcords[0][1];
259
for(a=1; a<moves; a++) {
260
if(mcords[a][0]<rect->xmin) rect->xmin= mcords[a][0];
261
else if(mcords[a][0]>rect->xmax) rect->xmax= mcords[a][0];
262
if(mcords[a][1]<rect->ymin) rect->ymin= mcords[a][1];
263
else if(mcords[a][1]>rect->ymax) rect->ymax= mcords[a][1];
267
static void do_lasso_select_mesh(short mcords[][2], short moves, short select)
269
extern int em_solidoffs, em_wireoffs; // let linker solve it... from editmesh_mods.c
270
EditMesh *em = G.editMesh;
275
int index, bbsel=0; // bbsel: no clip needed with screencoords
277
lasso_select_boundbox(&rect, mcords, moves);
279
bbsel= EM_mask_init_backbuf_border(mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
281
if(G.scene->selectmode & SCE_SELECT_VERTEX) {
282
if(bbsel==0) calc_meshverts_ext(); /* clips, drawobject.c */
284
for(eve= em->verts.first; eve; eve= eve->next, index++) {
287
if(EM_check_backbuf_border(index)) {
288
if(select) eve->f|= 1;
292
else if(eve->xs>rect.xmin && eve->xs<rect.xmax && eve->ys>rect.ymin && eve->ys<rect.ymax) {
293
if(lasso_inside(mcords, moves, eve->xs, eve->ys)) {
294
if(select) eve->f|= 1;
301
if(G.scene->selectmode & SCE_SELECT_EDGE) {
304
calc_meshverts_ext_f2(); /* doesnt clip, drawobject.c */
307
/* two stages, for nice edge select first do 'both points in rect'
308
also when bbsel is true */
309
for(eed= em->edges.first; eed; eed= eed->next, index++) {
311
if(edge_fully_inside_rect(rect, eed->v1->xs, eed->v1->ys, eed->v2->xs, eed->v2->ys)) {
312
if(lasso_inside(mcords, moves, eed->v1->xs, eed->v1->ys)) {
313
if(lasso_inside(mcords, moves, eed->v2->xs, eed->v2->ys)) {
314
if(EM_check_backbuf_border(index)) {
315
EM_select_edge(eed, select);
326
for(eed= em->edges.first; eed; eed= eed->next, index++) {
329
if(EM_check_backbuf_border(index))
330
EM_select_edge(eed, select);
332
else if(lasso_inside_edge(mcords, moves, &eed->v1->xs, &eed->v2->xs)) {
333
EM_select_edge(eed, select);
340
if(G.scene->selectmode & SCE_SELECT_FACE) {
341
if(bbsel==0) calc_mesh_facedots_ext();
343
for(efa= em->faces.first; efa; efa= efa->next, index++) {
346
if(EM_check_backbuf_border(index)) {
347
EM_select_face_fgon(efa, select);
350
else if(efa->xs>rect.xmin && efa->xs<rect.xmax && efa->ys>rect.ymin && efa->ys<rect.ymax) {
351
if(lasso_inside(mcords, moves, efa->xs, efa->ys)) {
352
EM_select_face_fgon(efa, select);
359
EM_free_backbuf_border();
360
EM_selectmode_flush();
364
static void do_lasso_select_curve(short mcords[][2], short moves, short select)
371
calc_nurbverts_ext(); /* drawobject.c */
374
if((nu->type & 7)==CU_BEZIER) {
379
if(lasso_inside(mcords, moves, bezt->s[0][0], bezt->s[0][1])) {
380
if(select) bezt->f1|= 1;
383
if(lasso_inside(mcords, moves, bezt->s[1][0], bezt->s[1][1])) {
384
if(select) bezt->f2|= 1;
387
if(lasso_inside(mcords, moves, bezt->s[2][0], bezt->s[2][1])) {
388
if(select) bezt->f3|= 1;
397
a= nu->pntsu*nu->pntsv;
400
if(lasso_inside(mcords, moves, bp->s[0], bp->s[1])) {
401
if(select) bp->f1|= 1;
412
static void do_lasso_select_lattice(short mcords[][2], short moves, short select)
417
calc_lattverts_ext();
421
a= editLatt->pntsu*editLatt->pntsv*editLatt->pntsw;
424
if(lasso_inside(mcords, moves, bp->s[0], bp->s[1])) {
425
if(select) bp->f1|= 1;
434
static void do_lasso_select_facemode(short mcords[][2], short moves, short select)
436
extern int em_vertoffs; // still bad code, let linker solve for now
443
if(me==NULL || me->tface==NULL) return;
444
if(me->totface==0) return;
447
em_vertoffs= me->totface+1; // max index array
449
lasso_select_boundbox(&rect, mcords, moves);
450
EM_mask_init_backbuf_border(mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
452
for(a=1; a<=me->totface; a++, tface++) {
453
if(EM_check_backbuf_border(a)) {
454
if(select) tface->flag |= TF_SELECT;
455
else tface->flag &= ~TF_SELECT;
459
EM_free_backbuf_border();
461
allqueue(REDRAWVIEW3D, 0);
462
allqueue(REDRAWIMAGE, 0);
465
static void do_lasso_select(short mcords[][2], short moves, short select)
468
if(G.f & G_FACESELECT)
469
do_lasso_select_facemode(mcords, moves, select);
470
else if(G.f & (G_VERTEXPAINT|G_TEXTUREPAINT|G_WEIGHTPAINT))
473
do_lasso_select_objects(mcords, moves, select);
475
else if(G.obedit->type==OB_MESH)
476
do_lasso_select_mesh(mcords, moves, select);
477
else if(G.obedit->type==OB_CURVE || G.obedit->type==OB_SURF)
478
do_lasso_select_curve(mcords, moves, select);
479
else if(G.obedit->type==OB_LATTICE)
480
do_lasso_select_lattice(mcords, moves, select);
482
BIF_undo_push("Lasso select");
484
allqueue(REDRAWVIEW3D, 0);
488
/* un-draws and draws again */
489
static void draw_lasso_select(short mcords[][2], short moves, short end)
496
for(a=1; a<=moves-1; a++) {
497
sdrawXORline(mcords[a-1][0], mcords[a-1][1], mcords[a][0], mcords[a][1]);
499
sdrawXORline(mcords[moves-1][0], mcords[moves-1][1], mcords[0][0], mcords[0][1]);
503
for(a=1; a<=moves; a++) {
504
sdrawXORline(mcords[a-1][0], mcords[a-1][1], mcords[a][0], mcords[a][1]);
506
sdrawXORline(mcords[moves][0], mcords[moves][1], mcords[0][0], mcords[0][1]);
125
512
static char interpret_move(short mcord[][2], int count)
127
float x1, x2, y1, y2, d1, d2, inp, sq, mouse[MOVES][2];
514
float x1, x2, y1, y2, d1, d2, inp, sq, mouse[MOVES_GESTURE][2];
128
515
int i, j, dir = 0;
130
517
if (count <= 10) return ('g');
543
1023
int temp, a, dist=100;
544
1024
short hits, mval[2];
546
/* always start list from basact */
1026
/* always start list from basact in wire mode */
547
1027
startbase= FIRSTBASE;
548
1028
if(BASACT && BASACT->next) startbase= BASACT->next;
550
1030
getmouseco_areawin(mval);
1032
/* This block uses the control key to make the object selected by its centre point rather then its contents */
552
1033
if(G.obedit==0 && (G.qual & LR_CTRLKEY)) {
557
if(base->lay & G.vd->lay) {
559
project_short(base->object->obmat[3], &base->sx);
561
temp= abs(base->sx -mval[0]) + abs(base->sy -mval[1]);
562
if(base==BASACT) temp+=10;
1035
if(G.qual & LR_ALTKEY) basact= mouse_select_menu(NULL, 0, mval);
1040
if(base->lay & G.vd->lay) {
1042
project_short(base->object->obmat[3], &base->sx);
1044
temp= abs(base->sx -mval[0]) + abs(base->sy -mval[1]);
1045
if(base==BASACT) temp+=10;
1054
if(base==0) base= FIRSTBASE;
1055
if(base==startbase) break;
570
if(base==0) base= FIRSTBASE;
571
if(base==startbase) break;
574
/* complete redraw when: */
575
if(G.f & (G_VERTEXPAINT+G_FACESELECT+G_TEXTUREPAINT+G_WEIGHTPAINT)) allqueue(REDRAWVIEW3D, 0);
579
1060
hits= selectprojektie(buffer, mval[0]-7, mval[1]-7, mval[0]+7, mval[1]+7);
580
1061
if(hits==0) hits= selectprojektie(buffer, mval[0]-21, mval[1]-21, mval[0]+21, mval[1]+21);
586
if(base->lay & G.vd->lay) {
1065
if(G.qual & LR_ALTKEY) basact= mouse_select_menu(buffer, hits, mval);
1067
static short lastmval[2]={-100, -100};
1070
/* define if we use solid nearest select or not */
1071
if(G.vd->drawtype>OB_WIRE) {
1073
if( ABS(mval[0]-lastmval[0])<3 && ABS(mval[1]-lastmval[1])<3) {
1077
lastmval[0]= mval[0]; lastmval[1]= mval[1];
1080
unsigned int min= 0xFFFFFFFF;
1081
int selcol= 0, notcol=0;
1083
/* prevent not being able to select active object... */
1084
if(BASACT && (BASACT->flag & SELECT) && hits>1) notcol= BASACT->selcol;
587
1086
for(a=0; a<hits; a++) {
588
1087
/* index was converted */
589
if(base->selcol==buffer[ (4 * a) + 3 ]) basact= base;
595
if(base==0) base= FIRSTBASE;
596
if(base==startbase) break;
1088
if( min > buffer[4*a+1] && notcol!=buffer[4*a+3]) {
1090
selcol= buffer[4*a+3];
1095
if(base->lay & G.vd->lay) {
1096
if(base->selcol==selcol) break;
1100
if(base) basact= base;
1106
if(base->lay & G.vd->lay) {
1107
for(a=0; a<hits; a++) {
1108
/* index was converted */
1109
if(base->selcol==buffer[(4*a)+3]) {
1118
if(base==0) base= FIRSTBASE;
1119
if(base==startbase) break;
718
1270
allqueue(REDRAWVIEW3D, 0);
723
1274
/* used to be a bigger test, also included sector and life */
724
1275
if(G.obedit->type==OB_MESH) {
726
calc_meshverts_ext(); /* drawobject.c */
727
eve= em->verts.first;
729
if(eve->h==0 && eve->xs>rect.xmin && eve->xs<rect.xmax) {
730
if(eve->ys>rect.ymin && eve->ys<rect.ymax) {
731
if(val==LEFTMOUSE) eve->f|= 1;
1276
extern int em_solidoffs, em_wireoffs; // let linker solve it... from editmesh_mods.c
1277
EditMesh *em = G.editMesh;
1281
int index, bbsel=0; // bbsel: no clip needed with screencoords
1283
bbsel= EM_init_backbuf_border(rect.xmin, rect.ymin, rect.xmax, rect.ymax);
1285
if(G.scene->selectmode & SCE_SELECT_VERTEX) {
1286
if(bbsel==0) calc_meshverts_ext(); /* clips, drawobject.c */
1288
for(eve= em->verts.first; eve; eve= eve->next, index++) {
1290
if(bbsel || (eve->xs>rect.xmin && eve->xs<rect.xmax && eve->ys>rect.ymin && eve->ys<rect.ymax)) {
1291
if(EM_check_backbuf_border(index)) {
1292
if(val==LEFTMOUSE) eve->f|= 1;
1299
if(G.scene->selectmode & SCE_SELECT_EDGE) {
1302
calc_meshverts_ext_f2(); /* doesnt clip, drawobject.c */
1303
index= em_solidoffs;
1304
/* two stages, for nice edge select first do 'both points in rect'
1305
also when bbsel is true */
1306
for(eed= em->edges.first; eed; eed= eed->next, index++) {
1308
if(edge_fully_inside_rect(rect, eed->v1->xs, eed->v1->ys, eed->v2->xs, eed->v2->ys)) {
1309
if(EM_check_backbuf_border(index)) {
1310
EM_select_edge(eed, val==LEFTMOUSE);
1318
index= em_solidoffs;
1319
for(eed= em->edges.first; eed; eed= eed->next, index++) {
1322
if(EM_check_backbuf_border(index))
1323
EM_select_edge(eed, val==LEFTMOUSE);
1325
else if(edge_inside_rect(rect, eed->v1->xs, eed->v1->ys, eed->v2->xs, eed->v2->ys)) {
1326
EM_select_edge(eed, val==LEFTMOUSE);
1333
if(G.scene->selectmode & SCE_SELECT_FACE) {
1334
if(bbsel==0) calc_mesh_facedots_ext();
1336
for(efa= em->faces.first; efa; efa= efa->next, index++) {
1338
if(bbsel || (efa->xs>rect.xmin && efa->xs<rect.xmax && efa->ys>rect.ymin && efa->ys<rect.ymax)) {
1339
if(EM_check_backbuf_border(index)) {
1340
EM_select_face_fgon(efa, val==LEFTMOUSE);
1347
EM_free_backbuf_border();
1349
EM_selectmode_flush();
737
1350
allqueue(REDRAWVIEW3D, 0);
923
1546
XXX These callback functions are still dirty, because they call globals...
926
void mesh_selectionCB(int selecting, Object *editobj, short *mval, float rad)
1549
static void mesh_selectionCB(int selecting, Object *editobj, short *mval, float rad)
1551
extern int em_solidoffs, em_wireoffs; // let linker solve it... from editmesh_mods.c
928
1552
EditMesh *em = G.editMesh;
1557
int index, bbsel=0; // if bbsel we dont clip with screencoords
1558
short rads= (short)(rad+1.0);
1560
bbsel= EM_init_backbuf_circle(mval[0], mval[1], rads);
1562
if(G.scene->selectmode & SCE_SELECT_VERTEX) {
1563
if(bbsel==0) calc_meshverts_ext(); /* drawobject.c */
1565
for(eve= em->verts.first; eve; eve= eve->next, index++) {
1568
if(EM_check_backbuf_border(index)) {
1569
if(selecting==LEFTMOUSE) eve->f|= 1;
1578
if(selecting==LEFTMOUSE) eve->f|= 1;
932
calc_meshverts_ext(); /* drawobject.c */
933
eve= em->verts.first;
940
if(selecting==LEFTMOUSE) eve->f|= 1;
1586
if(G.scene->selectmode & SCE_SELECT_EDGE) {
1587
if(bbsel==0) calc_meshverts_ext_f2(); /* doesnt clip, drawobject.c */
1588
index= em_solidoffs;
1589
for(eed= em->edges.first; eed; eed= eed->next, index++) {
1591
if(bbsel || edge_inside_circle(mval[0], mval[1], (short)rad, eed->v1->xs, eed->v1->ys, eed->v2->xs, eed->v2->ys)) {
1592
if(EM_check_backbuf_border(index)) {
1593
EM_select_edge(eed, selecting==LEFTMOUSE);
1600
if(G.scene->selectmode & SCE_SELECT_FACE) {
1601
if(bbsel==0) calc_mesh_facedots_ext();
1603
for(efa= em->faces.first; efa; efa= efa->next, index++) {
1606
if(EM_check_backbuf_border(index)) {
1607
EM_select_face_fgon(efa, selecting==LEFTMOUSE);
1615
EM_select_face_fgon(efa, selecting==LEFTMOUSE);
1621
EM_free_backbuf_border();
1622
EM_selectmode_flush();
947
1624
draw_sel_circle(0, 0, 0, 0, 0); /* signal */
953
void nurbscurve_selectionCB(int selecting, Object *editobj, short *mval, float rad)
1630
static void nurbscurve_selectionCB(int selecting, Object *editobj, short *mval, float rad)
1064
/** The circle select function - should be replaced by the callback
1065
* version circle_selectCB(). Why ? Because it's not nice as it is!
1069
void circle_select(void)
1071
EditMesh *em = G.editMesh;
1076
static float rad= 40.0;
1077
float rado, x, y, trad;
1079
unsigned short event;
1080
short mvalo[2], mval[2], val;
1083
if(G.obedit==0) return;
1085
getmouseco_areawin(mvalo);
1086
draw_sel_circle(mvalo, 0, rad, 0.0, selecting);
1092
/* when a renderwindow is open and mouse enters it (activates sometimes) */
1094
mywinset(curarea->win);
1096
getmouseco_areawin(mval);
1098
if(mval[0]!=mvalo[0] || mval[1]!=mvalo[1] || rado!=rad || firsttime) {
1101
draw_sel_circle(mval, mvalo, rad, rado, selecting);
1109
if(G.obedit->type==OB_MESH) {
1111
calc_meshverts_ext(); /* drawobject.c */
1112
eve= em->verts.first;
1117
trad= sqrt(x*x+y*y);
1119
if(selecting==LEFTMOUSE) eve->f|= 1;
1125
draw_sel_circle(0, 0, 0, 0, 0); /* signal */
1128
else if ELEM(G.obedit->type, OB_CURVE, OB_SURF) {
1130
calc_nurbverts_ext(); /* drawobject.c */
1133
if((nu->type & 7)==CU_BEZIER) {
1138
x= bezt->s[0][0]-mval[0];
1139
y= bezt->s[0][1]-mval[1];
1140
trad= sqrt(x*x+y*y);
1142
if(selecting==LEFTMOUSE) bezt->f1|= 1;
1143
else bezt->f1 &= ~1;
1145
x= bezt->s[1][0]-mval[0];
1146
y= bezt->s[1][1]-mval[1];
1147
trad= sqrt(x*x+y*y);
1149
if(selecting==LEFTMOUSE) bezt->f2|= 1;
1150
else bezt->f2 &= ~1;
1152
x= bezt->s[2][0]-mval[0];
1153
y= bezt->s[2][1]-mval[1];
1154
trad= sqrt(x*x+y*y);
1156
if(selecting==LEFTMOUSE) bezt->f3|= 1;
1157
else bezt->f3 &= ~1;
1166
a= nu->pntsu*nu->pntsv;
1169
x= bp->s[0]-mval[0];
1170
y= bp->s[1]-mval[1];
1171
trad= sqrt(x*x+y*y);
1173
if(selecting==LEFTMOUSE) bp->f1|= 1;
1182
draw_sel_circle(0, 0, 0, 0, 0); /* signal */
1185
else if(G.obedit->type==OB_LATTICE) {
1186
calc_lattverts_ext();
1190
a= editLatt->pntsu*editLatt->pntsv*editLatt->pntsw;
1193
x= bp->s[0]-mval[0];
1194
y= bp->s[1]-mval[1];
1195
trad= sqrt(x*x+y*y);
1197
if(selecting==LEFTMOUSE) bp->f1|= 1;
1203
draw_sel_circle(0, 0, 0, 0, 0); /* signal */
1209
event= extern_qread(&val);
1216
if(val) selecting= event;
1222
if(val) if(rad<200.0) rad*= 1.2;
1225
if(val) if(rad>5.0) rad/= 1.2;
1228
case ESCKEY: case SPACEKEY: case RIGHTMOUSE:
1229
case GKEY: case SKEY: case RKEY: case XKEY: case EKEY: case TABKEY:
1240
draw_sel_circle(0, mvalo, 0, rad, 1);
1243
allqueue(REDRAWINFO, 0);
1246
1741
void set_render_border(void)