Two fixes;
[blender.git] / source / blender / src / editview.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL/BL DUAL 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. 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
12  * about this.
13  *
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.
18  *
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.
22  *
23  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
24  * All rights reserved.
25  *
26  * The Original Code is: all of this file.
27  *
28  * Contributor(s): none yet.
29  *
30  * ***** END GPL/BL DUAL LICENSE BLOCK *****
31  * cursor/gestures/selecteren
32  */
33
34 #include <stdlib.h>
35 #include <stdio.h>
36 #include <math.h>
37 #include <string.h>
38
39 #ifdef HAVE_CONFIG_H
40 #include <config.h>
41 #endif
42
43 #ifdef WIN32
44 #include "BLI_winstuff.h"
45 #endif
46
47 #include "IMB_imbuf.h"
48 #include "PIL_time.h"
49
50 #include "DNA_armature_types.h"
51 #include "DNA_meta_types.h"
52 #include "DNA_mesh_types.h"
53 #include "DNA_curve_types.h"
54 #include "DNA_lattice_types.h"
55 #include "DNA_object_types.h"
56 #include "DNA_scene_types.h"
57 #include "DNA_screen_types.h"
58 #include "DNA_view3d_types.h"
59 #include "DNA_userdef_types.h"
60
61 #include "BLI_blenlib.h"
62 #include "BLI_arithb.h"
63 #include "BLI_editVert.h"
64
65 #include "BKE_utildefines.h"
66 #include "BKE_global.h"
67 #include "BKE_armature.h"
68 #include "BKE_lattice.h"
69
70 #include "BIF_butspace.h"
71 #include "BIF_editarmature.h"
72 #include "BIF_editgroup.h"
73 #include "BIF_editmesh.h"
74 #include "BIF_editoops.h"
75 #include "BIF_editsima.h"
76 #include "BIF_editview.h"
77 #include "BIF_gl.h"
78 #include "BIF_glutil.h"
79 #include "BIF_interface.h"
80 #include "BIF_mywindow.h"
81 #include "BIF_space.h"
82 #include "BIF_screen.h"
83 #include "BIF_toolbox.h"
84
85 #include "BDR_editobject.h"     /* For headerprint */
86 #include "BDR_vpaint.h"
87 #include "BDR_editface.h"
88 #include "BDR_drawobject.h"
89 #include "BDR_editcurve.h"
90
91 #include "BSE_edit.h"
92 #include "BSE_view.h"           /* give_cursor() */
93 #include "BSE_editipo.h"
94 #include "BSE_drawview.h"
95 #include "BSE_editaction.h"
96
97 #include "editmesh.h"   // borderselect uses it...
98 #include "blendef.h"
99 #include "mydevice.h"
100
101 extern ListBase editNurb; /* originally from exports.h, memory from editcurve.c*/
102 /* editmball.c */
103 extern ListBase editelems;
104
105
106
107 void arrows_move_cursor(unsigned short event)
108 {
109         short mval[2];
110
111         getmouseco_sc(mval);
112
113         if(event==UPARROWKEY) {
114                 warp_pointer(mval[0], mval[1]+1);
115         } else if(event==DOWNARROWKEY) {
116                 warp_pointer(mval[0], mval[1]-1);
117         } else if(event==LEFTARROWKEY) {
118                 warp_pointer(mval[0]-1, mval[1]);
119         } else if(event==RIGHTARROWKEY) {
120                 warp_pointer(mval[0]+1, mval[1]);
121         }
122 }
123
124 /* *********************** GESTURE AND LASSO ******************* */
125
126 /* helper also for borderselect */
127 static int edge_fully_inside_rect(rcti rect, short x1, short y1, short x2, short y2)
128 {
129         
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;
133         
134         return 0;
135         
136 }
137
138 static int edge_inside_rect(rcti rect, short x1, short y1, short x2, short y2)
139 {
140         int d1, d2, d3, d4;
141         
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;
145         
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;
151         
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 );
157         
158         if(d1<0 && d2<0 && d3<0 && d4<0) return 0;
159         if(d1>0 && d2>0 && d3>0 && d4>0) return 0;
160         
161         return 1;
162 }
163
164
165 #define MOVES_GESTURE 50
166 #define MOVES_LASSO 500
167
168 static int lasso_inside(short mcords[][2], short moves, short sx, short sy)
169 {
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];
172         int a;
173         short *p1, *p2;
174         
175         p1= mcords[moves-1];
176         p2= mcords[0];
177         
178         /* first vector */
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]);
182         fp1[0]/= len;
183         fp1[1]/= len;
184         
185         for(a=0; a<moves; a++) {
186                 /* second vector */
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]);
190                 fp2[0]/= len;
191                 fp2[1]/= len;
192                 
193                 /* dot and angle and cross */
194                 dot= fp1[0]*fp2[0] + fp1[1]*fp2[1];
195                 ang= fabs(saacos(dot));
196
197                 cross= (float)((p1[1]-p2[1])*(p1[0]-sx) + (p2[0]-p1[0])*(p1[1]-sy));
198                 
199                 if(cross<0.0) angletot-= ang;
200                 else angletot+= ang;
201                 
202                 /* circulate */
203                 fp1[0]= fp2[0]; fp1[1]= fp2[1];
204                 p1= p2;
205                 p2= mcords[a+1];
206         }
207         
208         if( fabs(angletot) > 4.0 ) return 1;
209         return 0;
210 }
211
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)
214 {
215         int a;
216
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;
220         
221         /* no points in lasso, so we have to intersect with lasso edge */
222         
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;
226         }
227         
228         return 0;
229 }
230
231
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
234 */
235 static void do_lasso_select_objects(short mcords[][2], short moves, short select)
236 {
237         Base *base;
238         
239         for(base= G.scene->base.first; base; base= base->next) {
240                 if(base->lay & G.vd->lay) {
241                         if(lasso_inside(mcords, moves, base->sx, base->sy)) {
242                                 
243                                 if(select) base->flag |= SELECT;
244                                 else base->flag &= ~SELECT;
245                                 base->object->flag= base->flag;
246                         }
247                 }
248         }
249 }
250
251 static void lasso_select_boundbox(rcti *rect, short mcords[][2], short moves)
252 {
253         short a;
254         
255         rect->xmin= rect->xmax= mcords[0][0];
256         rect->ymin= rect->ymax= mcords[0][1];
257         
258         for(a=1; a<moves; a++) {
259                 if(mcords[a][0]<rect->xmin) rect->xmin= mcords[a][0];
260                 else if(mcords[a][0]>rect->xmax) rect->xmax= mcords[a][0];
261                 if(mcords[a][1]<rect->ymin) rect->ymin= mcords[a][1];
262                 else if(mcords[a][1]>rect->ymax) rect->ymax= mcords[a][1];
263         }
264 }
265
266 static void do_lasso_select_mesh(short mcords[][2], short moves, short select)
267 {
268         extern int em_solidoffs, em_wireoffs;   // let linker solve it... from editmesh_mods.c 
269         EditMesh *em = G.editMesh;
270         EditVert *eve;
271         EditEdge *eed;
272         EditFace *efa;
273         rcti rect;
274         int index, bbsel=0; // bbsel: no clip needed with screencoords
275         
276         lasso_select_boundbox(&rect, mcords, moves);
277         
278         bbsel= EM_mask_init_backbuf_border(mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
279         
280         if(G.scene->selectmode & SCE_SELECT_VERTEX) {
281                 if(bbsel==0) calc_meshverts_ext();      /* clips, drawobject.c */
282                 index= em_wireoffs;
283                 for(eve= em->verts.first; eve; eve= eve->next, index++) {
284                         if(eve->h==0) {
285                                 if(bbsel) {
286                                         if(EM_check_backbuf_border(index)) {
287                                                 if(select) eve->f|= 1;
288                                                 else eve->f&= 254;
289                                         }
290                                 }
291                                 else if(eve->xs>rect.xmin && eve->xs<rect.xmax && eve->ys>rect.ymin && eve->ys<rect.ymax) {
292                                         if(lasso_inside(mcords, moves, eve->xs, eve->ys)) {
293                                                 if(select) eve->f|= 1;
294                                                 else eve->f&= 254;
295                                         }
296                                 }
297                         }
298                 }
299         }
300         if(G.scene->selectmode & SCE_SELECT_EDGE) {
301                 short done= 0;
302                 
303                 calc_meshverts_ext_f2();        /* doesnt clip, drawobject.c */
304                 index= em_solidoffs;
305                 
306                 /* two stages, for nice edge select first do 'both points in rect' 
307                         also when bbsel is true */
308                 for(eed= em->edges.first; eed; eed= eed->next, index++) {
309                         if(eed->h==0) {
310                                 if(edge_fully_inside_rect(rect, eed->v1->xs, eed->v1->ys,  eed->v2->xs, eed->v2->ys)) {
311                                         if(lasso_inside(mcords, moves, eed->v1->xs, eed->v1->ys)) {
312                                                 if(lasso_inside(mcords, moves, eed->v2->xs, eed->v2->ys)) {
313                                                         if(EM_check_backbuf_border(index)) {
314                                                                 EM_select_edge(eed, select);
315                                                                 done = 1;
316                                                         }
317                                                 }
318                                         }
319                                 }
320                         }
321                 }
322                 
323                 if(done==0) {
324                         index= em_solidoffs;
325                         for(eed= em->edges.first; eed; eed= eed->next, index++) {
326                                 if(eed->h==0) {
327                                         if(bbsel) {
328                                                 if(EM_check_backbuf_border(index))
329                                                         EM_select_edge(eed, select);
330                                         }
331                                         else if(lasso_inside_edge(mcords, moves, &eed->v1->xs, &eed->v2->xs)) {
332                                                 EM_select_edge(eed, select);
333                                         }
334                                 }
335                         }
336                 }
337         }
338         
339         if(G.scene->selectmode & SCE_SELECT_FACE) {
340                 if(bbsel==0) calc_mesh_facedots_ext();
341                 index= 1;
342                 for(efa= em->faces.first; efa; efa= efa->next, index++) {
343                         if(efa->h==0) {
344                                 if(bbsel) {
345                                         if(EM_check_backbuf_border(index)) {
346                                                 EM_select_face_fgon(efa, select);
347                                         }
348                                 }
349                                 else if(efa->xs>rect.xmin && efa->xs<rect.xmax && efa->ys>rect.ymin && efa->ys<rect.ymax) {
350                                         if(lasso_inside(mcords, moves, efa->xs, efa->ys)) {
351                                                 EM_select_face_fgon(efa, select);
352                                         }
353                                 }
354                         }
355                 }
356         }
357         
358         EM_free_backbuf_border();
359         EM_selectmode_flush();
360         
361 }
362
363 static void do_lasso_select(short mcords[][2], short moves, short select)
364 {
365         /* first simple object centers */
366         if(G.obedit==NULL) 
367                 do_lasso_select_objects(mcords, moves, select);
368         else if(G.obedit->type==OB_MESH) 
369                 do_lasso_select_mesh(mcords, moves, select);
370
371         BIF_undo_push("Lasso select");
372
373         allqueue(REDRAWVIEW3D, 0);
374         countall();
375 }
376
377 /* un-draws and draws again */
378 static void draw_lasso_select(short mcords[][2], short moves, short end)
379 {
380         int a;
381         
382         setlinestyle(2);
383         /* clear draw */
384         if(moves>1) {
385                 for(a=1; a<=moves-1; a++) {
386                         sdrawXORline(mcords[a-1][0], mcords[a-1][1], mcords[a][0], mcords[a][1]);
387                 }
388                 sdrawXORline(mcords[moves-1][0], mcords[moves-1][1], mcords[0][0], mcords[0][1]);
389         }
390         if(!end) {
391                 /* new draw */
392                 for(a=1; a<=moves; a++) {
393                         sdrawXORline(mcords[a-1][0], mcords[a-1][1], mcords[a][0], mcords[a][1]);
394                 }
395                 sdrawXORline(mcords[moves][0], mcords[moves][1], mcords[0][0], mcords[0][1]);
396         }
397         setlinestyle(0);
398 }
399
400
401 static char interpret_move(short mcord[][2], int count)
402 {
403         float x1, x2, y1, y2, d1, d2, inp, sq, mouse[MOVES_GESTURE][2];
404         int i, j, dir = 0;
405         
406         if (count <= 10) return ('g');
407
408         /* from short to float (drawing is with shorts) */
409         for(j=0; j<count; j++) {
410                 mouse[j][0]= mcord[j][0];
411                 mouse[j][1]= mcord[j][1];
412         }
413         
414         /* new method:
415          * 
416          * starting from end points, calculate centre with maximum distance
417          * dependant at the angle s / g / r is defined
418          */
419         
420
421         /* filter */
422         
423         for( j = 3 ; j > 0; j--){
424                 x1 = mouse[1][0];
425                 y1 = mouse[1][1];
426                 for (i = 2; i < count; i++){
427                         x2 = mouse[i-1][0];
428                         y2 = mouse[i-1][1];
429                         mouse[i-1][0] = ((x1 + mouse[i][0]) /4.0) + (x2 / 2.0);
430                         mouse[i-1][1] = ((y1 + mouse[i][1]) /4.0) + (y2 / 2.0);
431                         x1 = x2;
432                         y1 = y2;
433                 }
434         }
435
436         /* make overview of directions */
437         for (i = 0; i <= count - 2; i++){
438                 x1 = mouse[i][0] - mouse[i + 1][0];
439                 y1 = mouse[i][1] - mouse[i + 1][1];
440
441                 if (x1 < -0.5){
442                         if (y1 < -0.5) dir |= 32;
443                         else if (y1 > 0.5) dir |= 128;
444                         else dir |= 64;
445                 } else if (x1 > 0.5){
446                         if (y1 < -0.5) dir |= 8;
447                         else if (y1 > 0.5) dir |= 2;
448                         else dir |= 4;
449                 } else{
450                         if (y1 < -0.5) dir |= 16;
451                         else if (y1 > 0.5) dir |= 1;
452                         else dir |= 0;
453                 }
454         }
455         
456         /* move all crosses to the right */
457         for (i = 7; i>=0 ; i--){
458                 if (dir & 128) dir = (dir << 1) + 1;
459                 else break;
460         }
461         dir &= 255;
462         for (i = 7; i>=0 ; i--){
463                 if ((dir & 1) == 0) dir >>= 1;
464                 else break;
465         }
466         
467         /* in theory: 1 direction: straight line
468      * multiple sequential directions: circle
469      * non-sequential, and 1 bit set in upper 4 bits: size
470      */
471         switch(dir){
472         case 1:
473                 return ('g');
474                 break;
475         case 3:
476         case 7:
477                 x1 = mouse[0][0] - mouse[count >> 1][0];
478                 y1 = mouse[0][1] - mouse[count >> 1][1];
479                 x2 = mouse[count >> 1][0] - mouse[count - 1][0];
480                 y2 = mouse[count >> 1][1] - mouse[count - 1][1];
481                 d1 = (x1 * x1) + (y1 * y1);
482                 d2 = (x2 * x2) + (y2 * y2);
483                 sq = sqrt(d1);
484                 x1 /= sq; 
485                 y1 /= sq;
486                 sq = sqrt(d2);
487                 x2 /= sq; 
488                 y2 /= sq;
489                 inp = (x1 * x2) + (y1 * y2);
490                 /*printf("%f\n", inp);*/
491                 if (inp > 0.9) return ('g');
492                 else return ('r');
493                 break;
494         case 15:
495         case 31:
496         case 63:
497         case 127:
498         case 255:
499                 return ('r');
500                 break;
501         default:
502                 /* for size at least one of the higher bits has to be set */
503                 if (dir < 16) return ('r');
504                 else return ('s');
505         }
506
507         return (0);
508 }
509
510
511 /* return 1 to denote gesture did something, also does lasso */
512 int gesture(void)
513 {
514         short mcords[MOVES_LASSO][2]; // the larger size
515         int i= 1, end= 0, a;
516         unsigned short event=0;
517         short mval[2], val, timer=0, mousebut, lasso=0, maxmoves;
518         
519         glDrawBuffer(GL_FRONT);
520         persp(PERSP_WIN);       /*  ortho at pixel level */
521         
522         getmouseco_areawin(mval);
523         
524         mcords[0][0] = mval[0];
525         mcords[0][1] = mval[1];
526         
527         if (U.flag & USER_LMOUSESELECT) mousebut = R_MOUSE;
528         else mousebut = L_MOUSE;
529         
530         if(G.qual & LR_CTRLKEY) lasso= 1;
531         
532         if(lasso) maxmoves= MOVES_LASSO;
533         else maxmoves= MOVES_GESTURE;
534         
535         while(get_mbut() & mousebut) {
536                 
537                 if(qtest()) event= extern_qread(&val);
538                 else if(i==1) {
539                         /* not drawing yet... check for toolbox */
540                         PIL_sleep_ms(10);
541                         timer++;
542                         if(timer>=10*U.tb_leftmouse) {
543                                 glDrawBuffer(GL_BACK); /* !! */
544                                 toolbox_n();
545                                 return 1;
546                         }
547                 }
548                 
549                 switch (event) {
550                 case MOUSEY:
551                         getmouseco_areawin(mval);
552                         if( abs(mval[0]-mcords[i-1][0])>3 || abs(mval[1]-mcords[i-1][1])>3 ) {
553                                 mcords[i][0] = mval[0];
554                                 mcords[i][1] = mval[1];
555                                 
556                                 if(i) {
557                                         if(lasso) draw_lasso_select(mcords, i, 0);
558                                         else sdrawXORline(mcords[i-1][0], mcords[i-1][1], mcords[i][0], mcords[i][1]);
559                                         glFlush();
560                                 }
561                                 i++;
562                         }
563                         break;
564                 case MOUSEX:
565                         break;
566                 case LEFTMOUSE:
567                         break;
568                 default:
569                         if(event) end= 1;       /* blender returns 0 */
570                         break;
571                 }
572                 if (i == maxmoves || end == 1) break;
573         }
574         
575         /* clear */
576         if(lasso) draw_lasso_select(mcords, i, 1);
577         else for(a=1; a<i; a++) {
578                 sdrawXORline(mcords[a-1][0], mcords[a-1][1], mcords[a][0], mcords[a][1]);
579         }
580         
581         persp(PERSP_VIEW);
582         glDrawBuffer(GL_BACK);
583         
584         if (i > 2) {
585                 if(lasso) do_lasso_select(mcords, i, (G.qual & LR_SHIFTKEY)==0);
586                 else {
587                         i = interpret_move(mcords, i);
588                         
589                         if(i) {
590                                 if(curarea->spacetype==SPACE_IPO) transform_ipo(i);
591                                 else if(curarea->spacetype==SPACE_IMAGE) transform_tface_uv(i);
592                                 else if(curarea->spacetype==SPACE_OOPS) transform_oops('g');
593                                 else transform(i);
594                         }
595                 }
596                 return 1;
597         }
598         return 0;
599 }
600
601 void mouse_cursor(void)
602 {
603         extern float zfac;      /* view.c */
604         float dx, dy, fz, *fp = NULL, dvec[3], oldcurs[3];
605         short mval[2], mx, my, lr_click=0;
606         
607         if(gesture()) return;
608         
609         getmouseco_areawin(mval);
610         
611         if(mval[0]!=G.vd->mx || mval[1]!=G.vd->my) {
612
613                 mx= mval[0];
614                 my= mval[1];
615                 
616                 fp= give_cursor();
617                 
618                 if(G.obedit && ((G.qual & LR_CTRLKEY) || get_mbut()&R_MOUSE )) lr_click= 1;
619                 VECCOPY(oldcurs, fp);
620                 
621                 project_short_noclip(fp, mval);
622
623                 initgrabz(fp[0], fp[1], fp[2]);
624                 
625                 if(mval[0]!=3200) {
626                         
627                         window_to_3d(dvec, mval[0]-mx, mval[1]-my);
628                         VecSubf(fp, fp, dvec);
629                         
630                 }
631                 else {
632
633                         dx= ((float)(mx-(curarea->winx/2)))*zfac/(curarea->winx/2);
634                         dy= ((float)(my-(curarea->winy/2)))*zfac/(curarea->winy/2);
635                         
636                         fz= G.vd->persmat[0][3]*fp[0]+ G.vd->persmat[1][3]*fp[1]+ G.vd->persmat[2][3]*fp[2]+ G.vd->persmat[3][3];
637                         fz= fz/zfac;
638                         
639                         fp[0]= (G.vd->persinv[0][0]*dx + G.vd->persinv[1][0]*dy+ G.vd->persinv[2][0]*fz)-G.vd->ofs[0];
640                         fp[1]= (G.vd->persinv[0][1]*dx + G.vd->persinv[1][1]*dy+ G.vd->persinv[2][1]*fz)-G.vd->ofs[1];
641                         fp[2]= (G.vd->persinv[0][2]*dx + G.vd->persinv[1][2]*dy+ G.vd->persinv[2][2]*fz)-G.vd->ofs[2];
642                 }
643                 
644                 allqueue(REDRAWVIEW3D, 1);
645         }
646         
647         if(lr_click) {
648                 if(G.obedit->type==OB_MESH) addvert_mesh();
649                 else if ELEM(G.obedit->type, OB_CURVE, OB_SURF) addvert_Nurb(0);
650                 else if (G.obedit->type==OB_ARMATURE) addvert_armature();
651                 VECCOPY(fp, oldcurs);
652         }
653         
654 }
655
656 void deselectall(void)  /* is toggle */
657 {
658         Base *base;
659         int a=0;
660
661         base= FIRSTBASE;
662         while(base) {
663                 if TESTBASE(base) {
664                         a= 1;
665                         break;
666                 }
667                 base= base->next;
668         }
669         
670         base= FIRSTBASE;
671         while(base) {
672                 if(base->lay & G.vd->lay) {
673                         if(a) base->flag &= ~SELECT;
674                         else base->flag |= SELECT;
675                         base->object->flag= base->flag;
676                 }
677                 base= base->next;
678         }
679
680         allqueue(REDRAWVIEW3D, 0);
681         allqueue(REDRAWDATASELECT, 0);
682         allqueue(REDRAWNLA, 0);
683         
684         countall();
685         BIF_undo_push("(De)select all");
686 }
687
688 /* selects all objects of a particular type, on currently visible layers */
689 void selectall_type(short obtype) 
690 {
691         Base *base;
692         
693         base= FIRSTBASE;
694         while(base) {
695                 if((base->lay & G.vd->lay) && (base->object->type == obtype)) {
696                         base->flag |= SELECT;
697                         base->object->flag= base->flag;
698                 }
699                 base= base->next;
700         }
701
702         allqueue(REDRAWVIEW3D, 0);
703         allqueue(REDRAWDATASELECT, 0);
704         allqueue(REDRAWNLA, 0);
705         
706         countall();
707         BIF_undo_push("Select all per type");
708 }
709 /* selects all objects on a particular layer */
710 void selectall_layer(int layernum) 
711 {
712         Base *base;
713         
714         base= FIRSTBASE;
715         while(base) {
716                 if (base->lay == (1<< (layernum -1))) {
717                         base->flag |= SELECT;
718                         base->object->flag= base->flag;
719                 }
720                 base= base->next;
721         }
722
723         allqueue(REDRAWVIEW3D, 0);
724         allqueue(REDRAWDATASELECT, 0);
725         allqueue(REDRAWNLA, 0);
726         
727         countall();
728         BIF_undo_push("Select all per layer");
729 }
730
731 static void deselectall_except(Base *b)   /* deselect all except b */
732 {
733         Base *base;
734
735         base= FIRSTBASE;
736         while(base) {
737                 if (base->flag & SELECT) {
738                         if(b!=base) {
739                                 base->flag &= ~SELECT;
740                                 base->object->flag= base->flag;
741                         }
742                 }
743                 base= base->next;
744         }
745 }
746
747 #if 0
748 /* smart function to sample a rect spiralling outside, nice for backbuf selection */
749 static unsigned int samplerect(unsigned int *buf, int size, unsigned int dontdo)
750 {
751         Base *base;
752         unsigned int *bufmin,*bufmax;
753         int a,b,rc,tel,aantal,dirvec[4][2],maxob;
754         unsigned int retval=0;
755         
756         base= LASTBASE;
757         if(base==0) return 0;
758         maxob= base->selcol;
759
760         aantal= (size-1)/2;
761         rc= 0;
762
763         dirvec[0][0]= 1;
764         dirvec[0][1]= 0;
765         dirvec[1][0]= 0;
766         dirvec[1][1]= -size;
767         dirvec[2][0]= -1;
768         dirvec[2][1]= 0;
769         dirvec[3][0]= 0;
770         dirvec[3][1]= size;
771
772         bufmin= buf;
773         bufmax= buf+ size*size;
774         buf+= aantal*size+ aantal;
775
776         for(tel=1;tel<=size;tel++) {
777
778                 for(a=0;a<2;a++) {
779                         for(b=0;b<tel;b++) {
780
781                                 if(*buf && *buf<=maxob && *buf!=dontdo) return *buf;
782                                 if( *buf==dontdo ) retval= dontdo;      /* if only color dontdo is available, still return dontdo */
783                                 
784                                 buf+= (dirvec[rc][0]+dirvec[rc][1]);
785
786                                 if(buf<bufmin || buf>=bufmax) return retval;
787                         }
788                         rc++;
789                         rc &= 3;
790                 }
791         }
792         return retval;
793 }
794 #endif
795
796 #define SELECTSIZE      51
797
798 void set_active_base(Base *base)
799 {
800         
801         BASACT= base;
802         
803         if(base) {
804                 /* signals to buttons */
805                 redraw_test_buttons(base->object);
806
807                 set_active_group();
808                 
809                 /* signal to ipo */
810
811                 if (base) {
812                         allqueue(REDRAWIPO, base->object->ipowin);
813                         allqueue(REDRAWACTION, 0);
814                         allqueue(REDRAWNLA, 0);
815                 }
816         }
817 }
818
819 void set_active_object(Object *ob)
820 {
821         Base *base;
822         
823         base= FIRSTBASE;
824         while(base) {
825                 if(base->object==ob) {
826                         set_active_base(base);
827                         return;
828                 }
829                 base= base->next;
830         }
831 }
832
833 /* The max number of menu items in an object select menu */
834 #define SEL_MENU_SIZE 22
835
836 static Base *mouse_select_menu(unsigned int *buffer, int hits, short *mval)
837 {
838         Base *baseList[SEL_MENU_SIZE]={NULL}; /*baseList is used to store all possible bases to bring up a menu */
839         Base *base;
840         short baseCount = 0;
841         char menuText[20 + SEL_MENU_SIZE*32] = "Select Object%t";       // max ob name = 22
842         char str[32];
843         
844         for(base=FIRSTBASE; base; base= base->next) {
845                 if(base->lay & G.vd->lay) {
846                         baseList[baseCount] = NULL;
847                         
848                         /* two selection methods, the CTRL select uses max dist of 15 */
849                         if(buffer) {
850                                 int a;
851                                 for(a=0; a<hits; a++) {
852                                         /* index was converted */
853                                         if(base->selcol==buffer[ (4 * a) + 3 ]) baseList[baseCount] = base;
854                                 }
855                         }
856                         else {
857                                 int temp, dist=15;
858                                 
859                                 project_short(base->object->obmat[3], &base->sx);
860                                 
861                                 temp= abs(base->sx -mval[0]) + abs(base->sy -mval[1]);
862                                 if(temp<dist ) baseList[baseCount] = base;
863                         }
864                         
865                         if(baseList[baseCount]) {
866                                 if (baseCount < SEL_MENU_SIZE) {
867                                         baseList[baseCount] = base;
868                                         sprintf(str, "|%s %%x%d", base->object->id.name+2, baseCount+1);        // max ob name == 22
869                                         strcat(menuText, str);
870                                         baseCount++;
871                                 }
872                         }
873                 }
874         }
875         
876         if(baseCount<=1) return baseList[0];
877         else {
878                 baseCount = pupmenu(menuText);
879                 
880                 if (baseCount != -1) { /* If nothing is selected then dont do anything */
881                         return baseList[baseCount-1];
882                 }
883                 else return NULL;
884         }
885 }
886
887 void mouse_select(void)
888 {
889         Base *base, *startbase=NULL, *basact=NULL, *oldbasact=NULL;
890         unsigned int buffer[MAXPICKBUF];
891         int temp, a, dist=100;
892         short hits, mval[2];
893
894         /* always start list from basact */
895         startbase=  FIRSTBASE;
896         if(BASACT && BASACT->next) startbase= BASACT->next;
897
898         getmouseco_areawin(mval);
899         
900         /* This block uses the control key to make the object selected by its centre point rather then its contents */
901         if(G.obedit==0 && (G.qual & LR_CTRLKEY)) {
902                 
903                 if(G.qual & LR_ALTKEY) basact= mouse_select_menu(NULL, 0, mval);
904                 else {
905                         base= startbase;
906                         while(base) {
907                                 
908                                 if(base->lay & G.vd->lay) {
909                                         
910                                         project_short(base->object->obmat[3], &base->sx);
911                                         
912                                         temp= abs(base->sx -mval[0]) + abs(base->sy -mval[1]);
913                                         if(base==BASACT) temp+=10;
914                                         if(temp<dist ) {
915                                                 
916                                                 dist= temp;
917                                                 basact= base;
918                                         }
919                                 }
920                                 base= base->next;
921                                 
922                                 if(base==0) base= FIRSTBASE;
923                                 if(base==startbase) break;
924                         }
925                 }
926         }
927         else {
928                 hits= selectprojektie(buffer, mval[0]-7, mval[1]-7, mval[0]+7, mval[1]+7);
929                 if(hits==0) hits= selectprojektie(buffer, mval[0]-21, mval[1]-21, mval[0]+21, mval[1]+21);
930
931                 if(hits>0) {
932
933                         if(G.qual & LR_ALTKEY) basact= mouse_select_menu(buffer, hits, mval);
934                         else {
935                                 base= startbase;
936                                 while(base) {
937                                         if(base->lay & G.vd->lay) {
938                                                 for(a=0; a<hits; a++) {
939                                                         /* index was converted */
940                                                         if(base->selcol==buffer[ (4 * a) + 3 ]) {
941                                                                 basact= base;
942                                                         }
943                                                 }
944                                         }
945                                         
946                                         if(basact) break;
947                                         
948                                         base= base->next;
949                                         if(base==0) base= FIRSTBASE;
950                                         if(base==startbase) break;
951                                 }
952                         }
953                 }
954         }
955         
956         if(basact) {
957                 if(G.obedit) {
958                         /* only do select */
959                         deselectall_except(basact);
960                         basact->flag |= SELECT;
961                         draw_object_ext(basact);
962                 }
963                 else {
964                         oldbasact= BASACT;
965                         BASACT= basact;
966                         
967                         if((G.qual & LR_SHIFTKEY)==0) {
968                                 deselectall_except(basact);
969                                 basact->flag |= SELECT;
970                         }
971                         else {
972                                 if(basact->flag & SELECT) {
973                                         if(basact==oldbasact)
974                                                 basact->flag &= ~SELECT;
975                                 }
976                                 else basact->flag |= SELECT;
977                         }
978
979                         // copy
980                         basact->object->flag= basact->flag;
981                         
982                         if(oldbasact != basact) {
983                                 set_active_base(basact);
984                         }
985
986                         // for visual speed, only in wire mode
987                         if(G.vd->drawtype==OB_WIRE) {
988                                 if(oldbasact && oldbasact != basact && (oldbasact->lay & G.vd->lay)) 
989                                         draw_object_ext(oldbasact);
990                                 draw_object_ext(basact);
991                         }
992                         
993                         if(basact->object->type!=OB_MESH) {
994                                 if(G.f & G_WEIGHTPAINT) {
995                                         set_wpaint();   /* toggle */
996                                 }
997                                 if(G.f & G_VERTEXPAINT) {
998                                         set_vpaint();   /* toggle */
999                                 }
1000                                 if(G.f & G_FACESELECT) {
1001                                         set_faceselect();       /* toggle */
1002                                 }
1003                         }
1004                         /* also because multiple 3d windows can be open */
1005                         allqueue(REDRAWVIEW3D, 0);
1006
1007                         allqueue(REDRAWBUTSLOGIC, 0);
1008                         allqueue(REDRAWDATASELECT, 0);
1009                         allqueue(REDRAWBUTSOBJECT, 0);
1010                         allqueue(REDRAWACTION, 0);
1011                         allqueue(REDRAWNLA, 0);
1012                         allqueue(REDRAWHEADERS, 0);     /* To force display update for the posebutton */
1013                         
1014                 }
1015                 
1016         }
1017
1018         countall();
1019
1020         rightmouse_transform(); // does undo push!
1021 }
1022
1023 /* ------------------------------------------------------------------------- */
1024
1025 static int edge_inside_circle(short centx, short centy, short rad, short x1, short y1, short x2, short y2)
1026 {
1027         int radsq= rad*rad;
1028         float v1[2], v2[2], v3[2];
1029         
1030         // check points in circle itself
1031         if( (x1-centx)*(x1-centx) + (y1-centy)*(y1-centy) <= radsq ) return 1;
1032         if( (x2-centx)*(x2-centx) + (y2-centy)*(y2-centy) <= radsq ) return 1;
1033         
1034         // pointdistline
1035         v3[0]= centx;
1036         v3[1]= centy;
1037         v1[0]= x1;
1038         v1[1]= y1;
1039         v2[0]= x2;
1040         v2[1]= y2;
1041         
1042         if( PdistVL2Dfl(v3, v1, v2) < (float)rad ) return 1;
1043         
1044         return 0;
1045 }
1046
1047
1048 /**
1049  * Does the 'borderselect' command. (Select verts based on selecting with a 
1050  * border: key 'b'). All selecting seems to be done in the get_border part.
1051  */
1052 void borderselect(void)
1053 {
1054         rcti rect;
1055         Base *base;
1056         Nurb *nu;
1057         BezTriple *bezt;
1058         BPoint *bp;
1059         MetaElem *ml;
1060         unsigned int buffer[MAXPICKBUF];
1061         int a, index;
1062         short hits, val, tel;
1063
1064         if(G.obedit==0 && (G.f & G_FACESELECT)) {
1065                 face_borderselect();
1066                 return;
1067         }
1068         setlinestyle(2);
1069         val= get_border(&rect, 3);
1070         setlinestyle(0);
1071         if(val) {
1072                 if (G.obpose){
1073                         if(G.obpose->type==OB_ARMATURE) {
1074                                 Bone    *bone;
1075                                 hits= selectprojektie(buffer, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
1076                                 base= FIRSTBASE;
1077                                 for (a=0; a<hits; a++){
1078                                         index = buffer[(4*a)+3];
1079                                         if (val==LEFTMOUSE){
1080                                                 if (index != -1){
1081                                                         bone = get_indexed_bone(G.obpose->data, index &~(BONESEL_TIP|BONESEL_ROOT));
1082                                                         bone->flag |= BONE_SELECTED;
1083                                                         select_actionchannel_by_name(G.obpose->action, bone->name, 1);
1084                                                 }
1085                                         }
1086                                         else{   
1087                                                 if (index != -1){
1088                                                         bone = get_indexed_bone(G.obpose->data, index &~(BONESEL_TIP|BONESEL_ROOT));
1089                                                         bone->flag &= ~BONE_SELECTED;
1090                                                         select_actionchannel_by_name(G.obpose->action, bone->name, 0);
1091                                                 }
1092                                         }
1093                                 }
1094                                 
1095                                 allqueue(REDRAWBUTSEDIT, 0);
1096                                 allqueue(REDRAWBUTSOBJECT, 0);
1097                                 allqueue(REDRAWACTION, 0);
1098                                 allqueue(REDRAWNLA, 0);
1099                                 allqueue(REDRAWVIEW3D, 0);
1100                         }
1101                 }
1102                 else if(G.obedit) {
1103                         /* used to be a bigger test, also included sector and life */
1104                         if(G.obedit->type==OB_MESH) {
1105                                 extern int em_solidoffs, em_wireoffs;   // let linker solve it... from editmesh_mods.c 
1106                                 EditMesh *em = G.editMesh;
1107                                 EditVert *eve;
1108                                 EditEdge *eed;
1109                                 EditFace *efa;
1110                                 int index, bbsel=0; // bbsel: no clip needed with screencoords
1111                                 
1112                                 bbsel= EM_init_backbuf_border(rect.xmin, rect.ymin, rect.xmax, rect.ymax);
1113
1114                                 if(G.scene->selectmode & SCE_SELECT_VERTEX) {
1115                                         if(bbsel==0) calc_meshverts_ext();      /* clips, drawobject.c */
1116                                         index= em_wireoffs;
1117                                         for(eve= em->verts.first; eve; eve= eve->next, index++) {
1118                                                 if(eve->h==0) {
1119                                                         if(bbsel || (eve->xs>rect.xmin && eve->xs<rect.xmax && eve->ys>rect.ymin && eve->ys<rect.ymax)) {
1120                                                                 if(EM_check_backbuf_border(index)) {
1121                                                                         if(val==LEFTMOUSE) eve->f|= 1;
1122                                                                         else eve->f&= 254;
1123                                                                 }
1124                                                         }
1125                                                 }
1126                                         }
1127                                 }
1128                                 if(G.scene->selectmode & SCE_SELECT_EDGE) {
1129                                         short done= 0;
1130                                         
1131                                         calc_meshverts_ext_f2();        /* doesnt clip, drawobject.c */
1132                                         index= em_solidoffs;
1133                                         /* two stages, for nice edge select first do 'both points in rect'
1134                                            also when bbsel is true */
1135                                         for(eed= em->edges.first; eed; eed= eed->next, index++) {
1136                                                 if(eed->h==0) {
1137                                                         if(edge_fully_inside_rect(rect, eed->v1->xs, eed->v1->ys, eed->v2->xs, eed->v2->ys)) {
1138                                                                 if(EM_check_backbuf_border(index)) {
1139                                                                         EM_select_edge(eed, val==LEFTMOUSE);
1140                                                                         done = 1;
1141                                                                 }
1142                                                         }
1143                                                 }
1144                                         }
1145
1146                                         if(done==0) {
1147                                                 index= em_solidoffs;
1148                                                 for(eed= em->edges.first; eed; eed= eed->next, index++) {
1149                                                         if(eed->h==0) {
1150                                                                 if(bbsel) {
1151                                                                         if(EM_check_backbuf_border(index))
1152                                                                                 EM_select_edge(eed, val==LEFTMOUSE);
1153                                                                 }
1154                                                                 else if(edge_inside_rect(rect, eed->v1->xs, eed->v1->ys, eed->v2->xs, eed->v2->ys)) {
1155                                                                         EM_select_edge(eed, val==LEFTMOUSE);
1156                                                                 }
1157                                                         }
1158                                                 }
1159                                         }
1160                                 }
1161                                 
1162                                 if(G.scene->selectmode & SCE_SELECT_FACE) {
1163                                         if(bbsel==0) calc_mesh_facedots_ext();
1164                                         index= 1;
1165                                         for(efa= em->faces.first; efa; efa= efa->next, index++) {
1166                                                 if(efa->h==0) {
1167                                                         if(bbsel || (efa->xs>rect.xmin && efa->xs<rect.xmax && efa->ys>rect.ymin && efa->ys<rect.ymax)) {
1168                                                                 if(EM_check_backbuf_border(index)) {
1169                                                                         EM_select_face_fgon(efa, val==LEFTMOUSE);
1170                                                                 }
1171                                                         }
1172                                                 }
1173                                         }
1174                                 }
1175                                 
1176                                 EM_free_backbuf_border();
1177                                         
1178                                 EM_selectmode_flush();
1179                                 allqueue(REDRAWVIEW3D, 0);
1180                                 
1181                         }
1182                         else if ELEM(G.obedit->type, OB_CURVE, OB_SURF) {
1183                                 
1184                                 calc_nurbverts_ext();   /* drawobject.c */
1185                                 nu= editNurb.first;
1186                                 while(nu) {
1187                                         if((nu->type & 7)==CU_BEZIER) {
1188                                                 bezt= nu->bezt;
1189                                                 a= nu->pntsu;
1190                                                 while(a--) {
1191                                                         if(bezt->hide==0) {
1192                                                                 if(bezt->s[0][0]>rect.xmin && bezt->s[0][0]<rect.xmax) {
1193                                                                         if(bezt->s[0][1]>rect.ymin && bezt->s[0][1]<rect.ymax) {
1194                                                                                 if(val==LEFTMOUSE) bezt->f1|= 1;
1195                                                                                 else bezt->f1 &= ~1;
1196                                                                         }
1197                                                                 }
1198                                                                 if(bezt->s[1][0]>rect.xmin && bezt->s[1][0]<rect.xmax) {
1199                                                                         if(bezt->s[1][1]>rect.ymin && bezt->s[1][1]<rect.ymax) {
1200                                                                                 if(val==LEFTMOUSE) {
1201                                                                                         bezt->f1|= 1; bezt->f2|= 1; bezt->f3|= 1;
1202                                                                                 }
1203                                                                                 else {
1204                                                                                         bezt->f1 &= ~1; bezt->f2 &= ~1; bezt->f3 &= ~1;
1205                                                                                 }
1206                                                                         }
1207                                                                 }
1208                                                                 if(bezt->s[2][0]>rect.xmin && bezt->s[2][0]<rect.xmax) {
1209                                                                         if(bezt->s[2][1]>rect.ymin && bezt->s[2][1]<rect.ymax) {
1210                                                                                 if(val==LEFTMOUSE) bezt->f3|= 1;
1211                                                                                 else bezt->f3 &= ~1;
1212                                                                         }
1213                                                                 }
1214                                                         }
1215                                                         bezt++;
1216                                                 }
1217                                         }
1218                                         else {
1219                                                 bp= nu->bp;
1220                                                 a= nu->pntsu*nu->pntsv;
1221                                                 while(a--) {
1222                                                         if(bp->hide==0) {
1223                                                                 if(bp->s[0]>rect.xmin && bp->s[0]<rect.xmax) {
1224                                                                         if(bp->s[1]>rect.ymin && bp->s[1]<rect.ymax) {
1225                                                                                 if(val==LEFTMOUSE) bp->f1|= 1;
1226                                                                                 else bp->f1 &= ~1;
1227                                                                         }
1228                                                                 }
1229                                                         }
1230                                                         bp++;
1231                                                 }
1232                                         }
1233                                         nu= nu->next;
1234                                 }
1235                                 allqueue(REDRAWVIEW3D, 0);
1236                         }
1237                         else if(G.obedit->type==OB_MBALL) {
1238                                 hits= selectprojektie(buffer, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
1239                                 
1240                                 ml= editelems.first;
1241                                 
1242                                 while(ml) {
1243                                         for(a=0; a<hits; a++) {
1244                                                 if(ml->selcol==buffer[ (4 * a) + 3 ]) {
1245                                                         if(val==LEFTMOUSE) ml->flag |= SELECT;
1246                                                         else ml->flag &= ~SELECT;
1247                                                         break;
1248                                                 }
1249                                         }
1250                                         ml= ml->next;
1251                                 }
1252                                 allqueue(REDRAWVIEW3D, 0);
1253                         }
1254                         else if(G.obedit->type==OB_ARMATURE) {
1255                                 EditBone *ebone;
1256
1257                                 hits= selectprojektie(buffer, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
1258
1259                                 base= FIRSTBASE;
1260                                 for (a=0; a<hits; a++){
1261                                         index = buffer[(4*a)+3];
1262                                         if (val==LEFTMOUSE){
1263                                                 if (index!=-1){
1264                                                         ebone = BLI_findlink(&G.edbo, index & ~(BONESEL_TIP|BONESEL_ROOT));
1265                                                         if (index & BONESEL_TIP)
1266                                                                 ebone->flag |= BONE_TIPSEL;
1267                                                         if (index & BONESEL_ROOT)
1268                                                                 ebone->flag |= BONE_ROOTSEL;
1269                                                 }
1270                                         }
1271                                         else{
1272                                                 if (index!=-1){
1273                                                         ebone = BLI_findlink(&G.edbo, index & ~(BONESEL_TIP|BONESEL_ROOT));
1274                                                         if (index & BONESEL_TIP)
1275                                                                 ebone->flag &= ~BONE_TIPSEL;
1276                                                         if (index & BONESEL_ROOT)
1277                                                                 ebone->flag &= ~BONE_ROOTSEL;
1278                                                 }
1279                                         }
1280                                 }
1281                                 
1282                                 allqueue(REDRAWBUTSEDIT, 0);
1283                                 allqueue(REDRAWBUTSOBJECT, 0);
1284                                 allqueue(REDRAWACTION, 0);
1285                                 allqueue(REDRAWVIEW3D, 0);
1286                         }
1287                         else if(G.obedit->type==OB_LATTICE) {
1288                                 
1289                                 calc_lattverts_ext();
1290                                 
1291                                 bp= editLatt->def;
1292         
1293                                 a= editLatt->pntsu*editLatt->pntsv*editLatt->pntsw;
1294                                 while(a--) {
1295                                         if(bp->hide==0) {
1296                                                 if(bp->s[0]>rect.xmin && bp->s[0]<rect.xmax) {
1297                                                         if(bp->s[1]>rect.ymin && bp->s[1]<rect.ymax) {
1298                                                                 if(val==LEFTMOUSE) bp->f1|= 1;
1299                                                                 else bp->f1 &= ~1;
1300                                                         }
1301                                                 }
1302                                         }
1303                                         bp++;
1304                                 }
1305                                 allqueue(REDRAWVIEW3D, 0);
1306                         }
1307
1308                 }
1309                 else {
1310                         
1311                         hits= selectprojektie(buffer, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
1312
1313                         base= FIRSTBASE;
1314                         while(base) {
1315                                 if(base->lay & G.vd->lay) {
1316                                         for(a=0; a<hits; a++) {
1317                                                 /* converted index */
1318                                                 if(base->selcol==buffer[ (4 * a) + 3 ]) {
1319                                                         if(val==LEFTMOUSE) base->flag |= SELECT;
1320                                                         else base->flag &= ~SELECT;
1321                                                         base->object->flag= base->flag;
1322
1323                                                         draw_object_ext(base);
1324                                                         break;
1325                                                 }
1326                                         }
1327                                 }
1328                                 
1329                                 base= base->next;
1330                         }
1331                         /* frontbuffer flush */
1332                         glFlush();
1333                         
1334                         allqueue(REDRAWDATASELECT, 0);
1335                         
1336                         /* because backbuf drawing */
1337                         tel= 1;
1338                         base= FIRSTBASE;
1339                         while(base) {
1340                                 /* each base because of multiple windows */
1341                                 base->selcol = ((tel & 0xF00)<<12) 
1342                                         + ((tel & 0xF0)<<8) 
1343                                         + ((tel & 0xF)<<4);
1344                                 tel++;
1345                                 base= base->next;
1346                         }
1347                         /* new */
1348                         allqueue(REDRAWBUTSLOGIC, 0);
1349                         allqueue(REDRAWNLA, 0);
1350                 }
1351                 countall();
1352                 
1353                 allqueue(REDRAWINFO, 0);
1354         }
1355
1356         if(val) BIF_undo_push("Border select");
1357         
1358 } /* end of borderselect() */
1359
1360 /* ------------------------------------------------------------------------- */
1361
1362 /** The following functions are quick & dirty callback functions called
1363   * on the Circle select function (press B twice in Editmode)
1364   * They were torn out of the circle_select to make the latter more reusable
1365   * The callback version of circle_select (called circle_selectCB) was moved
1366   * to edit.c because of it's (wanted) generality.
1367
1368         XXX These callback functions are still dirty, because they call globals... 
1369   */
1370
1371 void mesh_selectionCB(int selecting, Object *editobj, short *mval, float rad)
1372 {
1373         extern int em_solidoffs, em_wireoffs;   // let linker solve it... from editmesh_mods.c 
1374         EditMesh *em = G.editMesh;
1375         EditVert *eve;
1376         EditEdge *eed;
1377         EditFace *efa;
1378         float x, y, r;
1379         int index, bbsel=0; // if bbsel we dont clip with screencoords
1380         short rads= (short)(rad+1.0);
1381         
1382         bbsel= EM_init_backbuf_circle(mval[0], mval[1], rads);
1383         
1384         if(G.scene->selectmode & SCE_SELECT_VERTEX) {
1385                 if(bbsel==0) calc_meshverts_ext();      /* drawobject.c */
1386                 index= em_wireoffs;
1387                 for(eve= em->verts.first; eve; eve= eve->next, index++) {
1388                         if(eve->h==0) {
1389                                 if(bbsel) {
1390                                         if(EM_check_backbuf_border(index)) {
1391                                                 if(selecting==LEFTMOUSE) eve->f|= 1;
1392                                                 else eve->f&= 254;
1393                                         }
1394                                 }
1395                                 else {
1396                                         x= eve->xs-mval[0];
1397                                         y= eve->ys-mval[1];
1398                                         r= sqrt(x*x+y*y);
1399                                         if(r<=rad) {
1400                                                 if(selecting==LEFTMOUSE) eve->f|= 1;
1401                                                 else eve->f&= 254;
1402                                         }
1403                                 }
1404                         }
1405                 }
1406         }
1407
1408         if(G.scene->selectmode & SCE_SELECT_EDGE) {
1409                 if(bbsel==0) calc_meshverts_ext_f2();   /* doesnt clip, drawobject.c */
1410                 index= em_solidoffs;
1411                 for(eed= em->edges.first; eed; eed= eed->next, index++) {
1412                         if(eed->h==0) {
1413                                 if(bbsel || edge_inside_circle(mval[0], mval[1], (short)rad, eed->v1->xs, eed->v1->ys,  eed->v2->xs, eed->v2->ys)) {
1414                                         if(EM_check_backbuf_border(index)) {
1415                                                 EM_select_edge(eed, selecting==LEFTMOUSE);
1416                                         }
1417                                 }
1418                         }
1419                 }
1420         }
1421         
1422         if(G.scene->selectmode & SCE_SELECT_FACE) {
1423                 if(bbsel==0) calc_mesh_facedots_ext();
1424                 index= 1;
1425                 for(efa= em->faces.first; efa; efa= efa->next, index++) {
1426                         if(efa->h==0) {
1427                                 if(bbsel) {
1428                                         if(EM_check_backbuf_border(index)) {
1429                                                 EM_select_face_fgon(efa, selecting==LEFTMOUSE);
1430                                         }
1431                                 }
1432                                 else {
1433                                         x= efa->xs-mval[0];
1434                                         y= efa->ys-mval[1];
1435                                         r= sqrt(x*x+y*y);
1436                                         if(r<=rad) {
1437                                                 EM_select_face_fgon(efa, selecting==LEFTMOUSE);
1438                                         }
1439                                 }
1440                         }
1441                 }
1442         }
1443         EM_free_backbuf_border();
1444         EM_selectmode_flush();
1445
1446         draw_sel_circle(0, 0, 0, 0, 0); /* signal */
1447         force_draw();
1448
1449 }
1450
1451
1452 void nurbscurve_selectionCB(int selecting, Object *editobj, short *mval, float rad)
1453 {
1454         Nurb *nu;
1455         BPoint *bp;
1456         BezTriple *bezt;
1457         float x, y, r;
1458         int a;
1459
1460         calc_nurbverts_ext();   /* drawobject.c */
1461         nu= editNurb.first;
1462         while(nu) {
1463                 if((nu->type & 7)==CU_BEZIER) {
1464                         bezt= nu->bezt;
1465                         a= nu->pntsu;
1466                         while(a--) {
1467                                 if(bezt->hide==0) {
1468                                         x= bezt->s[0][0]-mval[0];
1469                                         y= bezt->s[0][1]-mval[1];
1470                                         r= sqrt(x*x+y*y);
1471                                         if(r<=rad) {
1472                                                 if(selecting==LEFTMOUSE) bezt->f1|= 1;
1473                                                 else bezt->f1 &= ~1;
1474                                         }
1475                                         x= bezt->s[1][0]-mval[0];
1476                                         y= bezt->s[1][1]-mval[1];
1477                                         r= sqrt(x*x+y*y);
1478                                         if(r<=rad) {
1479                                                 if(selecting==LEFTMOUSE) bezt->f2|= 1;
1480                                                 else bezt->f2 &= ~1;
1481                                         }
1482                                         x= bezt->s[2][0]-mval[0];
1483                                         y= bezt->s[2][1]-mval[1];
1484                                         r= sqrt(x*x+y*y);
1485                                         if(r<=rad) {
1486                                                 if(selecting==LEFTMOUSE) bezt->f3|= 1;
1487                                                 else bezt->f3 &= ~1;
1488                                         }
1489                                         
1490                                 }
1491                                 bezt++;
1492                         }
1493                 }
1494                 else {
1495                         bp= nu->bp;
1496                         a= nu->pntsu*nu->pntsv;
1497                         while(a--) {
1498                                 if(bp->hide==0) {
1499                                         x= bp->s[0]-mval[0];
1500                                         y= bp->s[1]-mval[1];
1501                                         r= sqrt(x*x+y*y);
1502                                         if(r<=rad) {
1503                                                 if(selecting==LEFTMOUSE) bp->f1|= 1;
1504                                                 else bp->f1 &= ~1;
1505                                         }
1506                                 }
1507                                 bp++;
1508                         }
1509                 }
1510                 nu= nu->next;
1511         }
1512         draw_sel_circle(0, 0, 0, 0, 0); /* signal */
1513         force_draw();
1514
1515
1516 }
1517
1518 void lattice_selectionCB(int selecting, Object *editobj, short *mval, float rad)
1519 {
1520         BPoint *bp;
1521         float x, y, r;
1522         int a;
1523
1524         calc_lattverts_ext();
1525         
1526         bp= editLatt->def;
1527
1528         a= editLatt->pntsu*editLatt->pntsv*editLatt->pntsw;
1529         while(a--) {
1530                 if(bp->hide==0) {
1531                         x= bp->s[0]-mval[0];
1532                         y= bp->s[1]-mval[1];
1533                         r= sqrt(x*x+y*y);
1534                         if(r<=rad) {
1535                                 if(selecting==LEFTMOUSE) bp->f1|= 1;
1536                                 else bp->f1 &= ~1;
1537                         }
1538                 }
1539                 bp++;
1540         }
1541         draw_sel_circle(0, 0, 0, 0, 0); /* signal */
1542         force_draw();
1543 }
1544
1545 /** Callbacks for selection in Editmode */
1546
1547 void obedit_selectionCB(short selecting, Object *editobj, short *mval, float rad) 
1548 {
1549         switch(editobj->type) {         
1550         case OB_MESH:
1551                 mesh_selectionCB(selecting, editobj, mval, rad);
1552                 break;
1553         case OB_CURVE:
1554         case OB_SURF:
1555                 nurbscurve_selectionCB(selecting, editobj, mval, rad);
1556                 break;
1557         case OB_LATTICE:
1558                 lattice_selectionCB(selecting, editobj, mval, rad);
1559                 break;
1560         }
1561 }
1562
1563 void set_render_border(void)
1564 {
1565         rcti rect;
1566         short val;
1567
1568         if(G.vd->persp!=2) return;
1569         
1570         val= get_border(&rect, 2);
1571         if(val) {
1572                 rcti vb;
1573
1574                 calc_viewborder(G.vd, &vb);
1575
1576                 G.scene->r.border.xmin= (float) (rect.xmin-vb.xmin)/(vb.xmax-vb.xmin);
1577                 G.scene->r.border.ymin= (float) (rect.ymin-vb.ymin)/(vb.ymax-vb.ymin);
1578                 G.scene->r.border.xmax= (float) (rect.xmax-vb.xmin)/(vb.xmax-vb.xmin);
1579                 G.scene->r.border.ymax= (float) (rect.ymax-vb.ymin)/(vb.ymax-vb.ymin);
1580                 
1581                 CLAMP(G.scene->r.border.xmin, 0.0, 1.0);
1582                 CLAMP(G.scene->r.border.ymin, 0.0, 1.0);
1583                 CLAMP(G.scene->r.border.xmax, 0.0, 1.0);
1584                 CLAMP(G.scene->r.border.ymax, 0.0, 1.0);
1585                 
1586                 allqueue(REDRAWVIEWCAM, 1);
1587                 // if it was not set, we do this
1588                 G.scene->r.mode |= R_BORDER;
1589                 allqueue(REDRAWBUTSSCENE, 1);
1590         }
1591 }
1592
1593
1594
1595 void fly(void)
1596 {
1597         float speed=0.0, speedo=1.0, zspeed=0.0, dvec[3], *quat, mat[3][3];
1598         float oldvec[3], oldrot[3];
1599         int loop=1;
1600         unsigned short toets;
1601         short val, cent[2];
1602         short mval[2];
1603         
1604         if(curarea->spacetype!=SPACE_VIEW3D) return;
1605         if(G.vd->camera == 0) return;
1606         if(G.vd->persp<2) return;
1607         
1608         VECCOPY(oldvec, G.vd->camera->loc);
1609         VECCOPY(oldrot, G.vd->camera->rot);
1610         
1611         cent[0]= curarea->winrct.xmin+(curarea->winx)/2;
1612         cent[1]= curarea->winrct.ymin+(curarea->winy)/2;
1613         
1614         warp_pointer(cent[0], cent[1]);
1615         
1616         cent[0]=  (curarea->winx)/2;
1617         cent[1]=  (curarea->winy)/2;
1618         
1619         headerprint("Fly");
1620         
1621         while(loop) {
1622                 getmouseco_areawin(mval);
1623
1624                 while(qtest()) {
1625                         
1626                         toets= extern_qread(&val);
1627                         
1628                         if(val) {
1629                                 if(toets==ESCKEY) {
1630                                         VECCOPY(G.vd->camera->loc, oldvec);
1631                                         VECCOPY(G.vd->camera->rot, oldrot);
1632                                         loop= 0;
1633                                         break;
1634                                 }
1635                                 else if(toets==SPACEKEY) {
1636                                         loop= 0;
1637                                         BIF_undo_push("Fly camera");
1638                                         break;
1639                                 }
1640                                 else if(toets==LEFTMOUSE) {
1641                                         speed+= G.vd->grid/75.0;
1642                                         if(get_mbut()&M_MOUSE) speed= 0.0;
1643                                 }
1644                                 else if(toets==MIDDLEMOUSE) {
1645                                         speed-= G.vd->grid/75.0;
1646                                         if(get_mbut()&L_MOUSE) speed= 0.0;
1647                                 }
1648                         }
1649                 }
1650                 if(loop==0) break;
1651                 
1652                 /* define dvec */
1653                 val= mval[0]-cent[0];
1654                 if(val>20) val-= 20; else if(val< -20) val+= 20; else val= 0;
1655                 dvec[0]= 0.000001*val*val;
1656                 if(val>0) dvec[0]= -dvec[0];
1657                 
1658                 val= mval[1]-cent[1];
1659                 if(val>20) val-= 20; else if(val< -20) val+= 20; else val= 0;
1660                 dvec[1]= 0.000001*val*val;
1661                 if(val>0) dvec[1]= -dvec[1];
1662                 
1663                 dvec[2]= 1.0;
1664                 
1665                 zspeed= 0.0;
1666                 if(get_qual()&LR_CTRLKEY) zspeed= -G.vd->grid/25.0;
1667                 if(get_qual()&LR_ALTKEY) zspeed= G.vd->grid/25.0;
1668                 
1669                 if(speedo!=0.0 || zspeed!=0.0 || dvec[0]!=0.0 || dvec[1]!=0.0) {
1670                 
1671                         Normalise(dvec);
1672                         
1673                         Mat3CpyMat4(mat, G.vd->viewinv);
1674                         Mat3MulVecfl(mat, dvec);
1675                         quat= vectoquat(dvec, 5, 1);    /* track and upflag, not from the base: camera view calculation does not use that */
1676                         
1677                         QuatToEul(quat, G.vd->camera->rot);
1678                         
1679                         compatible_eul(G.vd->camera->rot, oldrot);
1680                         
1681                         VecMulf(dvec, speed);
1682                         G.vd->camera->loc[0]-= dvec[0];
1683                         G.vd->camera->loc[1]-= dvec[1];
1684                         G.vd->camera->loc[2]-= (dvec[2]-zspeed);
1685                         
1686                         scrarea_do_windraw(curarea);
1687                         screen_swapbuffers();
1688                 }
1689                 speedo= speed;
1690         }
1691         
1692         allqueue(REDRAWVIEW3D, 0);
1693         scrarea_queue_headredraw(curarea);
1694         
1695 }
1696