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