Final merge of HEAD (bf-blender) into the orange branch.
[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 #include "MEM_guardedalloc.h"
43
44 #include "IMB_imbuf.h"
45 #include "PIL_time.h"
46
47 #include "DNA_action_types.h"
48 #include "DNA_armature_types.h"
49 #include "DNA_curve_types.h"
50 #include "DNA_group_types.h"
51 #include "DNA_lattice_types.h"
52 #include "DNA_meta_types.h"
53 #include "DNA_mesh_types.h"
54 #include "DNA_object_types.h"
55 #include "DNA_scene_types.h"
56 #include "DNA_screen_types.h"
57 #include "DNA_view3d_types.h"
58 #include "DNA_userdef_types.h"
59
60 #include "BLI_blenlib.h"
61 #include "BLI_arithb.h"
62 #include "BLI_editVert.h"
63
64 #include "BKE_armature.h"
65 #include "BKE_depsgraph.h"
66 #include "BKE_global.h"
67 #include "BKE_group.h"
68 #include "BKE_lattice.h"
69 #include "BKE_main.h"
70 #include "BKE_mesh.h"
71 #include "BKE_utildefines.h"
72
73 #include "BIF_butspace.h"
74 #include "BIF_editaction.h"
75 #include "BIF_editarmature.h"
76 #include "BIF_editgroup.h"
77 #include "BIF_editmesh.h"
78 #include "BIF_editoops.h"
79 #include "BIF_editsima.h"
80 #include "BIF_editview.h"
81 #include "BIF_gl.h"
82 #include "BIF_glutil.h"
83 #include "BIF_interface.h"
84 #include "BIF_mywindow.h"
85 #include "BIF_space.h"
86 #include "BIF_screen.h"
87 #include "BIF_toolbox.h"
88
89 #include "BDR_editobject.h"     /* For headerprint */
90 #include "BDR_vpaint.h"
91 #include "BDR_editface.h"
92 #include "BDR_drawobject.h"
93 #include "BDR_editcurve.h"
94
95 #include "BSE_edit.h"
96 #include "BSE_view.h"           /* give_cursor() */
97 #include "BSE_editipo.h"
98 #include "BSE_drawview.h"
99
100 #include "editmesh.h"   // borderselect uses it...
101 #include "blendef.h"
102 #include "mydevice.h"
103
104 #include "BIF_transform.h"
105
106 extern ListBase editNurb; /* originally from exports.h, memory from editcurve.c*/
107 /* editmball.c */
108 extern ListBase editelems;
109
110 /* local prototypes */
111
112 void EM_backbuf_checkAndSelectVerts(EditMesh *em, int select)
113 {
114         EditVert *eve;
115         int index= em_wireoffs;
116
117         for(eve= em->verts.first; eve; eve= eve->next, index++) {
118                 if(eve->h==0) {
119                         if(EM_check_backbuf(index)) {
120                                 eve->f = select?(eve->f|1):(eve->f&~1);
121                         }
122                 }
123         }
124 }
125
126 void EM_backbuf_checkAndSelectEdges(EditMesh *em, int select)
127 {
128         EditEdge *eed;
129         int index= em_solidoffs;
130
131         for(eed= em->edges.first; eed; eed= eed->next, index++) {
132                 if(eed->h==0) {
133                         if(EM_check_backbuf(index)) {
134                                 EM_select_edge(eed, select);
135                         }
136                 }
137         }
138 }
139
140 void EM_backbuf_checkAndSelectFaces(EditMesh *em, int select)
141 {
142         EditFace *efa;
143         int index= 1;
144
145         for(efa= em->faces.first; efa; efa= efa->next, index++) {
146                 if(efa->h==0) {
147                         if(EM_check_backbuf(index)) {
148                                 EM_select_face_fgon(efa, select);
149                         }
150                 }
151         }
152 }
153
154 void EM_backbuf_checkAndSelectTFaces(Mesh *me, int select)
155 {
156         TFace *tface = me->tface;
157         int a;
158
159         if (tface) {
160                 for(a=1; a<=me->totface; a++, tface++) {
161                         if(EM_check_backbuf(a)) {
162                                 tface->flag = select?(tface->flag|TF_SELECT):(tface->flag&~TF_SELECT);
163                         }
164                 }
165         }
166 }
167
168 void arrows_move_cursor(unsigned short event)
169 {
170         short mval[2];
171
172         getmouseco_sc(mval);
173
174         if(event==UPARROWKEY) {
175                 warp_pointer(mval[0], mval[1]+1);
176         } else if(event==DOWNARROWKEY) {
177                 warp_pointer(mval[0], mval[1]-1);
178         } else if(event==LEFTARROWKEY) {
179                 warp_pointer(mval[0]-1, mval[1]);
180         } else if(event==RIGHTARROWKEY) {
181                 warp_pointer(mval[0]+1, mval[1]);
182         }
183 }
184
185 /* *********************** GESTURE AND LASSO ******************* */
186
187 /* helper also for borderselect */
188 static int edge_fully_inside_rect(rcti *rect, short x1, short y1, short x2, short y2)
189 {
190         return BLI_in_rcti(rect, x1, y1) && BLI_in_rcti(rect, x2, y2);
191 }
192
193 static int edge_inside_rect(rcti *rect, short x1, short y1, short x2, short y2)
194 {
195         int d1, d2, d3, d4;
196         
197         // check points in rect
198         if(edge_fully_inside_rect(rect, x1, y1, x2, y2)) return 1;
199         
200         // check points completely out rect
201         if(x1<rect->xmin && x2<rect->xmin) return 0;
202         if(x1>rect->xmax && x2>rect->xmax) return 0;
203         if(y1<rect->ymin && y2<rect->ymin) return 0;
204         if(y1>rect->ymax && y2>rect->ymax) return 0;
205         
206         // simple check lines intersecting. 
207         d1= (y1-y2)*(x1- rect->xmin ) + (x2-x1)*(y1- rect->ymin );
208         d2= (y1-y2)*(x1- rect->xmin ) + (x2-x1)*(y1- rect->ymax );
209         d3= (y1-y2)*(x1- rect->xmax ) + (x2-x1)*(y1- rect->ymax );
210         d4= (y1-y2)*(x1- rect->xmax ) + (x2-x1)*(y1- rect->ymin );
211         
212         if(d1<0 && d2<0 && d3<0 && d4<0) return 0;
213         if(d1>0 && d2>0 && d3>0 && d4>0) return 0;
214         
215         return 1;
216 }
217
218
219 #define MOVES_GESTURE 50
220 #define MOVES_LASSO 500
221
222 static int lasso_inside(short mcords[][2], short moves, short sx, short sy)
223 {
224         /* we do the angle rule, define that all added angles should be about zero or 2*PI */
225         float angletot=0.0, len, dot, ang, cross, fp1[2], fp2[2];
226         int a;
227         short *p1, *p2;
228         
229         p1= mcords[moves-1];
230         p2= mcords[0];
231         
232         /* first vector */
233         fp1[0]= (float)(p1[0]-sx);
234         fp1[1]= (float)(p1[1]-sy);
235         len= sqrt(fp1[0]*fp1[0] + fp1[1]*fp1[1]);
236         fp1[0]/= len;
237         fp1[1]/= len;
238         
239         for(a=0; a<moves; a++) {
240                 /* second vector */
241                 fp2[0]= (float)(p2[0]-sx);
242                 fp2[1]= (float)(p2[1]-sy);
243                 len= sqrt(fp2[0]*fp2[0] + fp2[1]*fp2[1]);
244                 fp2[0]/= len;
245                 fp2[1]/= len;
246                 
247                 /* dot and angle and cross */
248                 dot= fp1[0]*fp2[0] + fp1[1]*fp2[1];
249                 ang= fabs(saacos(dot));
250
251                 cross= (float)((p1[1]-p2[1])*(p1[0]-sx) + (p2[0]-p1[0])*(p1[1]-sy));
252                 
253                 if(cross<0.0) angletot-= ang;
254                 else angletot+= ang;
255                 
256                 /* circulate */
257                 fp1[0]= fp2[0]; fp1[1]= fp2[1];
258                 p1= p2;
259                 p2= mcords[a+1];
260         }
261         
262         if( fabs(angletot) > 4.0 ) return 1;
263         return 0;
264 }
265
266 /* edge version for lasso select. we assume boundbox check was done */
267 static int lasso_inside_edge(short mcords[][2], short moves, int x0, int y0, int x1, int y1)
268 {
269         short v1[2], v2[2];
270         int a;
271
272         v1[0] = x0, v1[1] = y0;
273         v2[0] = x1, v2[1] = y1;
274
275         // check points in lasso
276         if(lasso_inside(mcords, moves, v1[0], v1[1])) return 1;
277         if(lasso_inside(mcords, moves, v2[0], v2[1])) return 1;
278         
279         /* no points in lasso, so we have to intersect with lasso edge */
280         
281         if( IsectLL2Ds(mcords[0], mcords[moves-1], v1, v2) > 0) return 1;
282         for(a=0; a<moves-1; a++) {
283                 if( IsectLL2Ds(mcords[a], mcords[a+1], v1, v2) > 0) return 1;
284         }
285         
286         return 0;
287 }
288
289
290 /* warning; lasso select with backbuffer-check draws in backbuf with persp(PERSP_WIN) 
291    and returns with persp(PERSP_VIEW). After lasso select backbuf is not OK
292 */
293 static void do_lasso_select_pose(Object *ob, short mcords[][2], short moves, short select)
294 {
295         bPoseChannel *pchan;
296         float vec[3];
297         short sco1[2], sco2[2];
298         
299         if(ob->type!=OB_ARMATURE || ob->pose==NULL) return;
300         
301         for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
302                 VECCOPY(vec, pchan->pose_head);
303                 Mat4MulVecfl(ob->obmat, vec);
304                 project_short(vec, sco1);
305                 VECCOPY(vec, pchan->pose_tail);
306                 Mat4MulVecfl(ob->obmat, vec);
307                 project_short(vec, sco2);
308                 
309                 if(lasso_inside_edge(mcords, moves, sco1[0], sco1[1], sco2[0], sco2[1])) {
310                         if(select) pchan->bone->flag |= BONE_SELECTED;
311                         else pchan->bone->flag &= ~(BONE_ACTIVE|BONE_SELECTED);
312                 }
313         }
314 }
315
316
317 static void do_lasso_select_objects(short mcords[][2], short moves, short select)
318 {
319         Base *base;
320         
321         for(base= G.scene->base.first; base; base= base->next) {
322                 if(base->lay & G.vd->lay) {
323                         project_short(base->object->obmat[3], &base->sx);
324                         if(lasso_inside(mcords, moves, base->sx, base->sy)) {
325                                 
326                                 if(select) base->flag |= SELECT;
327                                 else base->flag &= ~SELECT;
328                                 base->object->flag= base->flag;
329                         }
330                         if(base->object->flag & OB_POSEMODE) {
331                                 do_lasso_select_pose(base->object, mcords, moves, select);
332                         }
333                 }
334         }
335 }
336
337 static void lasso_select_boundbox(rcti *rect, short mcords[][2], short moves)
338 {
339         short a;
340         
341         rect->xmin= rect->xmax= mcords[0][0];
342         rect->ymin= rect->ymax= mcords[0][1];
343         
344         for(a=1; a<moves; a++) {
345                 if(mcords[a][0]<rect->xmin) rect->xmin= mcords[a][0];
346                 else if(mcords[a][0]>rect->xmax) rect->xmax= mcords[a][0];
347                 if(mcords[a][1]<rect->ymin) rect->ymin= mcords[a][1];
348                 else if(mcords[a][1]>rect->ymax) rect->ymax= mcords[a][1];
349         }
350 }
351
352 static void do_lasso_select_mesh__doSelectVert(void *userData, EditVert *eve, int x, int y, int index)
353 {
354         struct { rcti *rect; short (*mcords)[2], moves, select, pass, done; } *data = userData;
355
356         if (BLI_in_rcti(data->rect, x, y) && lasso_inside(data->mcords, data->moves, x, y)) {
357                 eve->f = data->select?(eve->f|1):(eve->f&~1);
358         }
359 }
360 static void do_lasso_select_mesh__doSelectEdge(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index)
361 {
362         struct { rcti *rect; short (*mcords)[2], moves, select, pass, done; } *data = userData;
363
364         if (EM_check_backbuf(em_solidoffs+index)) {
365                 if (data->pass==0) {
366                         if (    edge_fully_inside_rect(data->rect, x0, y0, x1, y1)  &&
367                                         lasso_inside(data->mcords, data->moves, x0, y0) &&
368                                         lasso_inside(data->mcords, data->moves, x1, y1)) {
369                                 EM_select_edge(eed, data->select);
370                                 data->done = 1;
371                         }
372                 } else {
373                         if (lasso_inside_edge(data->mcords, data->moves, x0, y0, x1, y1)) {
374                                 EM_select_edge(eed, data->select);
375                         }
376                 }
377         }
378 }
379 static void do_lasso_select_mesh__doSelectFace(void *userData, EditFace *efa, int x, int y, int index)
380 {
381         struct { rcti *rect; short (*mcords)[2], moves, select, pass, done; } *data = userData;
382
383         if (BLI_in_rcti(data->rect, x, y) && lasso_inside(data->mcords, data->moves, x, y)) {
384                 EM_select_face_fgon(efa, data->select);
385         }
386 }
387
388 static void do_lasso_select_mesh(short mcords[][2], short moves, short select)
389 {
390         struct { rcti *rect; short (*mcords)[2], moves, select, pass, done; } data;
391         EditMesh *em = G.editMesh;
392         rcti rect;
393         int bbsel;
394         
395         lasso_select_boundbox(&rect, mcords, moves);
396         
397         data.rect = &rect;
398         data.mcords = mcords;
399         data.moves = moves;
400         data.select = select;
401         data.done = 0;
402         data.pass = 0;
403
404         bbsel= EM_mask_init_backbuf_border(mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
405         
406         if(G.scene->selectmode & SCE_SELECT_VERTEX) {
407                 if (bbsel) {
408                         EM_backbuf_checkAndSelectVerts(em, select);
409                 } else {
410                         mesh_foreachScreenVert(do_lasso_select_mesh__doSelectVert, &data, 1);
411                 }
412         }
413         if(G.scene->selectmode & SCE_SELECT_EDGE) {
414                         /* Does both bbsel and non-bbsel versions (need screen cos for both) */
415
416                 data.pass = 0;
417                 mesh_foreachScreenEdge(do_lasso_select_mesh__doSelectEdge, &data, 0);
418
419                 if (data.done==0) {
420                         data.pass = 1;
421                         mesh_foreachScreenEdge(do_lasso_select_mesh__doSelectEdge, &data, 0);
422                 }
423         }
424         
425         if(G.scene->selectmode & SCE_SELECT_FACE) {
426                 if (bbsel) {
427                         EM_backbuf_checkAndSelectFaces(em, select);
428                 } else {
429                         mesh_foreachScreenFace(do_lasso_select_mesh__doSelectFace, &data);
430                 }
431         }
432         
433         EM_free_backbuf();
434         EM_selectmode_flush();  
435 }
436
437 static void do_lasso_select_curve__doSelect(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y)
438 {
439         struct { short (*mcords)[2]; short moves; short select; } *data = userData;
440
441         if (lasso_inside(data->mcords, data->moves, x, y)) {
442                 if (bp) {
443                         bp->f1 = data->select?(bp->f1|1):(bp->f1&~1);
444                 } else {
445                         if (beztindex==0) {
446                                 bezt->f1 = data->select?(bezt->f1|1):(bezt->f1&~1);
447                         } else if (beztindex==1) {
448                                 bezt->f2 = data->select?(bezt->f2|1):(bezt->f2&~1);
449                         } else {
450                                 bezt->f3 = data->select?(bezt->f3|1):(bezt->f3&~1);
451                         }
452                 }
453         }
454 }
455 static void do_lasso_select_curve(short mcords[][2], short moves, short select)
456 {
457         struct { short (*mcords)[2]; short moves; short select; } data;
458
459         data.mcords = mcords;
460         data.moves = moves;
461         data.select = select;
462
463         nurbs_foreachScreenVert(do_lasso_select_curve__doSelect, &data);
464 }
465
466 static void do_lasso_select_lattice__doSelect(void *userData, BPoint *bp, int x, int y)
467 {
468         struct { short (*mcords)[2]; short moves; short select; } *data = userData;
469
470         if (lasso_inside(data->mcords, data->moves, x, y)) {
471                 bp->f1 = data->select?(bp->f1|1):(bp->f1&~1);
472         }
473 }
474 static void do_lasso_select_lattice(short mcords[][2], short moves, short select)
475 {
476         struct { short (*mcords)[2]; short moves; short select; } data;
477
478         data.mcords = mcords;
479         data.moves = moves;
480         data.select = select;
481
482         lattice_foreachScreenVert(do_lasso_select_lattice__doSelect, &data);
483 }
484
485 static void do_lasso_select_armature(short mcords[][2], short moves, short select)
486 {
487         EditBone *ebone;
488         float vec[3];
489         short sco1[2], sco2[2], didpoint;
490         
491         for (ebone=G.edbo.first; ebone; ebone=ebone->next) {
492
493                 VECCOPY(vec, ebone->head);
494                 Mat4MulVecfl(G.obedit->obmat, vec);
495                 project_short(vec, sco1);
496                 VECCOPY(vec, ebone->tail);
497                 Mat4MulVecfl(G.obedit->obmat, vec);
498                 project_short(vec, sco2);
499                 
500                 didpoint= 0;
501                 if(lasso_inside(mcords, moves, sco1[0], sco1[1])) {
502                         if(select) ebone->flag |= BONE_ROOTSEL;
503                         else ebone->flag &= ~BONE_ROOTSEL;
504                         didpoint= 1;
505                 }
506                 if(lasso_inside(mcords, moves, sco2[0], sco2[1])) {
507                    if(select) ebone->flag |= BONE_TIPSEL;
508                    else ebone->flag &= ~BONE_TIPSEL;
509                    didpoint= 1;
510                 }
511                 /* if one of points selected, we skip the bone itself */
512                 if(didpoint==0 && lasso_inside_edge(mcords, moves, sco1[0], sco1[1], sco2[0], sco2[1])) {
513                         if(select) ebone->flag |= BONE_TIPSEL|BONE_ROOTSEL|BONE_SELECTED;
514                         else ebone->flag &= ~(BONE_ACTIVE|BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL);
515                 }
516         }
517         countall();     // abused for flushing selection
518 }
519
520 static void do_lasso_select_facemode(short mcords[][2], short moves, short select)
521 {
522         Mesh *me;
523         rcti rect;
524         
525         me= get_mesh(OBACT);
526         if(me==NULL || me->tface==NULL) return;
527         if(me->totface==0) return;
528         
529         em_vertoffs= me->totface+1;     // max index array
530         
531         lasso_select_boundbox(&rect, mcords, moves);
532         EM_mask_init_backbuf_border(mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
533         
534         EM_backbuf_checkAndSelectTFaces(me, select);
535         
536         EM_free_backbuf();
537         
538         object_tface_flags_changed(OBACT, 0);
539 }
540
541 static void do_lasso_select(short mcords[][2], short moves, short select)
542 {
543         if(G.obedit==NULL) {
544                 if(G.f & G_FACESELECT)
545                         do_lasso_select_facemode(mcords, moves, select);
546                 else if(G.f & (G_VERTEXPAINT|G_TEXTUREPAINT|G_WEIGHTPAINT))
547                         ;
548                 else  
549                         do_lasso_select_objects(mcords, moves, select);
550         }
551         else if(G.obedit->type==OB_MESH) 
552                 do_lasso_select_mesh(mcords, moves, select);
553         else if(G.obedit->type==OB_CURVE || G.obedit->type==OB_SURF) 
554                 do_lasso_select_curve(mcords, moves, select);
555         else if(G.obedit->type==OB_LATTICE) 
556                 do_lasso_select_lattice(mcords, moves, select);
557         else if(G.obedit->type==OB_ARMATURE)
558                 do_lasso_select_armature(mcords, moves, select);
559         
560         BIF_undo_push("Lasso select");
561
562         allqueue(REDRAWVIEW3D, 0);
563         countall();
564 }
565
566 /* un-draws and draws again */
567 static void draw_lasso_select(short mcords[][2], short moves, short end)
568 {
569         int a;
570         
571         setlinestyle(2);
572         /* clear draw */
573         if(moves>1) {
574                 for(a=1; a<=moves-1; a++) {
575                         sdrawXORline(mcords[a-1][0], mcords[a-1][1], mcords[a][0], mcords[a][1]);
576                 }
577                 sdrawXORline(mcords[moves-1][0], mcords[moves-1][1], mcords[0][0], mcords[0][1]);
578         }
579         if(!end) {
580                 /* new draw */
581                 for(a=1; a<=moves; a++) {
582                         sdrawXORline(mcords[a-1][0], mcords[a-1][1], mcords[a][0], mcords[a][1]);
583                 }
584                 sdrawXORline(mcords[moves][0], mcords[moves][1], mcords[0][0], mcords[0][1]);
585         }
586         setlinestyle(0);
587 }
588
589
590 static char interpret_move(short mcord[][2], int count)
591 {
592         float x1, x2, y1, y2, d1, d2, inp, sq, mouse[MOVES_GESTURE][2];
593         int i, j, dir = 0;
594         
595         if (count <= 10) return ('g');
596
597         /* from short to float (drawing is with shorts) */
598         for(j=0; j<count; j++) {
599                 mouse[j][0]= mcord[j][0];
600                 mouse[j][1]= mcord[j][1];
601         }
602         
603         /* new method:
604          * 
605          * starting from end points, calculate centre with maximum distance
606          * dependant at the angle s / g / r is defined
607          */
608         
609
610         /* filter */
611         
612         for( j = 3 ; j > 0; j--){
613                 x1 = mouse[1][0];
614                 y1 = mouse[1][1];
615                 for (i = 2; i < count; i++){
616                         x2 = mouse[i-1][0];
617                         y2 = mouse[i-1][1];
618                         mouse[i-1][0] = ((x1 + mouse[i][0]) /4.0) + (x2 / 2.0);
619                         mouse[i-1][1] = ((y1 + mouse[i][1]) /4.0) + (y2 / 2.0);
620                         x1 = x2;
621                         y1 = y2;
622                 }
623         }
624
625         /* make overview of directions */
626         for (i = 0; i <= count - 2; i++){
627                 x1 = mouse[i][0] - mouse[i + 1][0];
628                 y1 = mouse[i][1] - mouse[i + 1][1];
629
630                 if (x1 < -0.5){
631                         if (y1 < -0.5) dir |= 32;
632                         else if (y1 > 0.5) dir |= 128;
633                         else dir |= 64;
634                 } else if (x1 > 0.5){
635                         if (y1 < -0.5) dir |= 8;
636                         else if (y1 > 0.5) dir |= 2;
637                         else dir |= 4;
638                 } else{
639                         if (y1 < -0.5) dir |= 16;
640                         else if (y1 > 0.5) dir |= 1;
641                         else dir |= 0;
642                 }
643         }
644         
645         /* move all crosses to the right */
646         for (i = 7; i>=0 ; i--){
647                 if (dir & 128) dir = (dir << 1) + 1;
648                 else break;
649         }
650         dir &= 255;
651         for (i = 7; i>=0 ; i--){
652                 if ((dir & 1) == 0) dir >>= 1;
653                 else break;
654         }
655         
656         /* in theory: 1 direction: straight line
657      * multiple sequential directions: circle
658      * non-sequential, and 1 bit set in upper 4 bits: size
659      */
660         switch(dir){
661         case 1:
662                 return ('g');
663                 break;
664         case 3:
665         case 7:
666                 x1 = mouse[0][0] - mouse[count >> 1][0];
667                 y1 = mouse[0][1] - mouse[count >> 1][1];
668                 x2 = mouse[count >> 1][0] - mouse[count - 1][0];
669                 y2 = mouse[count >> 1][1] - mouse[count - 1][1];
670                 d1 = (x1 * x1) + (y1 * y1);
671                 d2 = (x2 * x2) + (y2 * y2);
672                 sq = sqrt(d1);
673                 x1 /= sq; 
674                 y1 /= sq;
675                 sq = sqrt(d2);
676                 x2 /= sq; 
677                 y2 /= sq;
678                 inp = (x1 * x2) + (y1 * y2);
679                 /*printf("%f\n", inp);*/
680                 if (inp > 0.9) return ('g');
681                 else return ('r');
682                 break;
683         case 15:
684         case 31:
685         case 63:
686         case 127:
687         case 255:
688                 return ('r');
689                 break;
690         default:
691                 /* for size at least one of the higher bits has to be set */
692                 if (dir < 16) return ('r');
693                 else return ('s');
694         }
695
696         return (0);
697 }
698
699
700 /* return 1 to denote gesture did something, also does lasso */
701 int gesture(void)
702 {
703         unsigned short event=0;
704         int i= 1, end= 0, a;
705         short mcords[MOVES_LASSO][2]; // the larger size
706         short mval[2], val, timer=0, mousebut, lasso=0, maxmoves;
707         
708         if (U.flag & USER_LMOUSESELECT) mousebut = R_MOUSE;
709         else mousebut = L_MOUSE;
710         
711         /* check for lasso */
712         if(G.qual & LR_CTRLKEY) {
713                 if(curarea->spacetype==SPACE_VIEW3D) {
714                         if(G.obedit==NULL) {
715                                 if(G.f & (G_VERTEXPAINT|G_TEXTUREPAINT|G_WEIGHTPAINT)) return 0;
716                         }
717                         lasso= 1;
718                 }
719         }
720         
721         glDrawBuffer(GL_FRONT);
722         persp(PERSP_WIN);       /*  ortho at pixel level */
723         
724         getmouseco_areawin(mval);
725         
726         mcords[0][0] = mval[0];
727         mcords[0][1] = mval[1];
728         
729         if(lasso) maxmoves= MOVES_LASSO;
730         else maxmoves= MOVES_GESTURE;
731         
732         while(get_mbut() & mousebut) {
733                 
734                 if(qtest()) event= extern_qread(&val);
735                 else if(i==1) {
736                         /* not drawing yet... check for toolbox */
737                         PIL_sleep_ms(10);
738                         timer++;
739                         if(timer>=10*U.tb_leftmouse) {
740                                 glDrawBuffer(GL_BACK); /* !! */
741                                 toolbox_n();
742                                 return 1;
743                         }
744                 }
745                 
746                 switch (event) {
747                 case MOUSEY:
748                         getmouseco_areawin(mval);
749                         if( abs(mval[0]-mcords[i-1][0])>3 || abs(mval[1]-mcords[i-1][1])>3 ) {
750                                 mcords[i][0] = mval[0];
751                                 mcords[i][1] = mval[1];
752                                 
753                                 if(i) {
754                                         if(lasso) draw_lasso_select(mcords, i, 0);
755                                         else sdrawXORline(mcords[i-1][0], mcords[i-1][1], mcords[i][0], mcords[i][1]);
756                                         glFlush();
757                                 }
758                                 i++;
759                         }
760                         break;
761                 case MOUSEX:
762                         break;
763                 case LEFTMOUSE:
764                         break;
765                 default:
766                         if(event) end= 1;       /* blender returns 0 */
767                         break;
768                 }
769                 if (i == maxmoves || end == 1) break;
770         }
771         
772         /* clear */
773         if(lasso) draw_lasso_select(mcords, i, 1);
774         else for(a=1; a<i; a++) {
775                 sdrawXORline(mcords[a-1][0], mcords[a-1][1], mcords[a][0], mcords[a][1]);
776         }
777         
778         persp(PERSP_VIEW);
779         glDrawBuffer(GL_BACK);
780         
781         if (i > 2) {
782                 if(lasso) do_lasso_select(mcords, i, (G.qual & LR_SHIFTKEY)==0);
783                 else {
784                         i = interpret_move(mcords, i);
785                         
786                         if(i) {
787                                 if(curarea->spacetype==SPACE_IPO) transform_ipo(i);
788                                 else if(curarea->spacetype==SPACE_OOPS) transform_oops('g', 0);
789                                 else {
790                                         int context;
791
792                                         if(curarea->spacetype==SPACE_IMAGE) context= CTX_NONE;
793                                         else context= CTX_NONE;
794
795                                         if(i=='g') {
796                                                 initTransform(TFM_TRANSLATION, context);
797                                                 Transform();
798                                         }
799                                         else if(i=='r') {
800                                                 initTransform(TFM_ROTATION, context);
801                                                 Transform();
802                                         }
803                                         else {
804                                                 initTransform(TFM_RESIZE, context);
805                                                 Transform();
806                                         }
807                                 }
808                         }
809                 }
810                 return 1;
811         }
812         return 0;
813 }
814
815 void mouse_cursor(void)
816 {
817         extern float zfac;      /* view.c */
818         float dx, dy, fz, *fp = NULL, dvec[3], oldcurs[3];
819         short mval[2], mx, my, lr_click=0;
820         
821         if(gesture()) return;
822         
823         getmouseco_areawin(mval);
824
825         mx= mval[0];
826         my= mval[1];
827         
828         fp= give_cursor();
829         
830         if(G.obedit && ((G.qual & LR_CTRLKEY) || get_mbut()&R_MOUSE )) lr_click= 1;
831         VECCOPY(oldcurs, fp);
832         
833         project_short_noclip(fp, mval);
834
835         initgrabz(fp[0], fp[1], fp[2]);
836         
837         if(mval[0]!=IS_CLIPPED) {
838                 
839                 window_to_3d(dvec, mval[0]-mx, mval[1]-my);
840                 VecSubf(fp, fp, dvec);
841                 
842         }
843         else {
844
845                 dx= ((float)(mx-(curarea->winx/2)))*zfac/(curarea->winx/2);
846                 dy= ((float)(my-(curarea->winy/2)))*zfac/(curarea->winy/2);
847                 
848                 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];
849                 fz= fz/zfac;
850                 
851                 fp[0]= (G.vd->persinv[0][0]*dx + G.vd->persinv[1][0]*dy+ G.vd->persinv[2][0]*fz)-G.vd->ofs[0];
852                 fp[1]= (G.vd->persinv[0][1]*dx + G.vd->persinv[1][1]*dy+ G.vd->persinv[2][1]*fz)-G.vd->ofs[1];
853                 fp[2]= (G.vd->persinv[0][2]*dx + G.vd->persinv[1][2]*dy+ G.vd->persinv[2][2]*fz)-G.vd->ofs[2];
854         }
855         
856         allqueue(REDRAWVIEW3D, 1);
857         
858         if(lr_click) {
859                 if(G.obedit->type==OB_MESH) add_click_mesh();
860                 else if ELEM(G.obedit->type, OB_CURVE, OB_SURF) addvert_Nurb(0);
861                 else if (G.obedit->type==OB_ARMATURE) addvert_armature();
862                 VECCOPY(fp, oldcurs);
863         }
864         
865 }
866
867 void deselectall(void)  /* is toggle */
868 {
869         Base *base;
870         int a=0;
871
872         base= FIRSTBASE;
873         while(base) {
874                 if TESTBASE(base) {
875                         a= 1;
876                         break;
877                 }
878                 base= base->next;
879         }
880         
881         base= FIRSTBASE;
882         while(base) {
883                 if(base->lay & G.vd->lay) {
884                         if(a) base->flag &= ~SELECT;
885                         else base->flag |= SELECT;
886                         base->object->flag= base->flag;
887                 }
888                 base= base->next;
889         }
890
891         allqueue(REDRAWVIEW3D, 0);
892         allqueue(REDRAWDATASELECT, 0);
893         allqueue(REDRAWNLA, 0);
894         
895         countall();
896         BIF_undo_push("(De)select all");
897 }
898
899 /* inverts object selection */
900 void selectswap(void)
901 {
902         Base *base;
903
904         for(base= FIRSTBASE; base; base= base->next) {
905                 if(base->lay & G.vd->lay) {
906                         if TESTBASE(base) base->flag &= ~SELECT;
907                         else base->flag |= SELECT;
908                         base->object->flag= base->flag;
909                 }
910         }
911
912         allqueue(REDRAWVIEW3D, 0);
913         allqueue(REDRAWDATASELECT, 0);
914         allqueue(REDRAWNLA, 0);
915         
916         countall();
917         BIF_undo_push("Select Inverse");
918 }
919
920
921 /* selects all objects of a particular type, on currently visible layers */
922 void selectall_type(short obtype) 
923 {
924         Base *base;
925         
926         base= FIRSTBASE;
927         while(base) {
928                 if((base->lay & G.vd->lay) && (base->object->type == obtype)) {
929                         base->flag |= SELECT;
930                         base->object->flag= base->flag;
931                 }
932                 base= base->next;
933         }
934
935         allqueue(REDRAWVIEW3D, 0);
936         allqueue(REDRAWDATASELECT, 0);
937         allqueue(REDRAWNLA, 0);
938         
939         countall();
940         BIF_undo_push("Select all per type");
941 }
942 /* selects all objects on a particular layer */
943 void selectall_layer(unsigned int layernum) 
944 {
945         Base *base;
946         
947         base= FIRSTBASE;
948         while(base) {
949                 if (base->lay == (1<< (layernum -1))) {
950                         base->flag |= SELECT;
951                         base->object->flag= base->flag;
952                 }
953                 base= base->next;
954         }
955
956         allqueue(REDRAWVIEW3D, 0);
957         allqueue(REDRAWDATASELECT, 0);
958         allqueue(REDRAWNLA, 0);
959         
960         countall();
961         BIF_undo_push("Select all per layer");
962 }
963
964 static void deselectall_except(Base *b)   /* deselect all except b */
965 {
966         Base *base;
967
968         base= FIRSTBASE;
969         while(base) {
970                 if (base->flag & SELECT) {
971                         if(b!=base) {
972                                 base->flag &= ~SELECT;
973                                 base->object->flag= base->flag;
974                         }
975                 }
976                 base= base->next;
977         }
978 }
979
980 #if 0
981 /* smart function to sample a rect spiralling outside, nice for backbuf selection */
982 static unsigned int samplerect(unsigned int *buf, int size, unsigned int dontdo)
983 {
984         Base *base;
985         unsigned int *bufmin,*bufmax;
986         int a,b,rc,tel,aantal,dirvec[4][2],maxob;
987         unsigned int retval=0;
988         
989         base= LASTBASE;
990         if(base==0) return 0;
991         maxob= base->selcol;
992
993         aantal= (size-1)/2;
994         rc= 0;
995
996         dirvec[0][0]= 1;
997         dirvec[0][1]= 0;
998         dirvec[1][0]= 0;
999         dirvec[1][1]= -size;
1000         dirvec[2][0]= -1;
1001         dirvec[2][1]= 0;
1002         dirvec[3][0]= 0;
1003         dirvec[3][1]= size;
1004
1005         bufmin= buf;
1006         bufmax= buf+ size*size;
1007         buf+= aantal*size+ aantal;
1008
1009         for(tel=1;tel<=size;tel++) {
1010
1011                 for(a=0;a<2;a++) {
1012                         for(b=0;b<tel;b++) {
1013
1014                                 if(*buf && *buf<=maxob && *buf!=dontdo) return *buf;
1015                                 if( *buf==dontdo ) retval= dontdo;      /* if only color dontdo is available, still return dontdo */
1016                                 
1017                                 buf+= (dirvec[rc][0]+dirvec[rc][1]);
1018
1019                                 if(buf<bufmin || buf>=bufmax) return retval;
1020                         }
1021                         rc++;
1022                         rc &= 3;
1023                 }
1024         }
1025         return retval;
1026 }
1027 #endif
1028
1029 void set_active_base(Base *base)
1030 {
1031         Base *tbase;
1032         
1033         BASACT= base;
1034         
1035         if(base) {
1036                 
1037                 /* signals to buttons */
1038                 redraw_test_buttons(base->object);
1039                 
1040                 /* signal to ipo */
1041                 allqueue(REDRAWIPO, base->object->ipowin);
1042                 
1043                 allqueue(REDRAWACTION, 0);
1044                 allqueue(REDRAWNLA, 0);
1045                 allqueue(REDRAWNODE, 0);
1046                 
1047                 /* signal to action */
1048                 select_actionchannel_by_name(base->object->action, "Object", 1);
1049                 
1050                 /* disable temporal locks */
1051                 for(tbase=FIRSTBASE; tbase; tbase= tbase->next) {
1052                         if(base!=tbase && (tbase->object->shapeflag & OB_SHAPE_TEMPLOCK)) {
1053                                 tbase->object->shapeflag &= ~OB_SHAPE_TEMPLOCK;
1054                                 DAG_object_flush_update(G.scene, tbase->object, OB_RECALC_DATA);
1055                         }
1056                 }
1057         }
1058 }
1059
1060 void set_active_object(Object *ob)
1061 {
1062         Base *base;
1063         
1064         for(base= FIRSTBASE; base; base= base->next) {
1065                 if(base->object==ob) {
1066                         set_active_base(base);
1067                         return;
1068                 }
1069         }
1070 }
1071
1072 static void select_all_from_groups(Base *basact)
1073 {
1074         Group *group;
1075         GroupObject *go;
1076         int deselect= basact->flag & SELECT;
1077         
1078         for(group= G.main->group.first; group; group= group->id.next) {
1079                 if(object_in_group(basact->object, group)) {
1080                         for(go= group->gobject.first; go; go= go->next) {
1081                                 if(deselect) go->ob->flag &= ~SELECT;
1082                                 else go->ob->flag |= SELECT;
1083                         }
1084                 }
1085         }
1086         /* sync bases */
1087         for(basact= G.scene->base.first; basact; basact= basact->next) {
1088                 if(basact->object->flag & SELECT)
1089                         basact->flag |= SELECT;
1090                 else
1091                         basact->flag &= ~SELECT;
1092         }
1093 }
1094
1095 /* The max number of menu items in an object select menu */
1096 #define SEL_MENU_SIZE 22
1097
1098 static Base *mouse_select_menu(unsigned int *buffer, int hits, short *mval)
1099 {
1100         Base *baseList[SEL_MENU_SIZE]={NULL}; /*baseList is used to store all possible bases to bring up a menu */
1101         Base *base;
1102         short baseCount = 0;
1103         char menuText[20 + SEL_MENU_SIZE*32] = "Select Object%t";       // max ob name = 22
1104         char str[32];
1105         
1106         for(base=FIRSTBASE; base; base= base->next) {
1107                 if(base->lay & G.vd->lay) {
1108                         baseList[baseCount] = NULL;
1109                         
1110                         /* two selection methods, the CTRL select uses max dist of 15 */
1111                         if(buffer) {
1112                                 int a;
1113                                 for(a=0; a<hits; a++) {
1114                                         /* index was converted */
1115                                         if(base->selcol==buffer[ (4 * a) + 3 ]) baseList[baseCount] = base;
1116                                 }
1117                         }
1118                         else {
1119                                 int temp, dist=15;
1120                                 
1121                                 project_short(base->object->obmat[3], &base->sx);
1122                                 
1123                                 temp= abs(base->sx -mval[0]) + abs(base->sy -mval[1]);
1124                                 if(temp<dist ) baseList[baseCount] = base;
1125                         }
1126                         
1127                         if(baseList[baseCount]) {
1128                                 if (baseCount < SEL_MENU_SIZE) {
1129                                         baseList[baseCount] = base;
1130                                         sprintf(str, "|%s %%x%d", base->object->id.name+2, baseCount+1);        // max ob name == 22
1131                                         strcat(menuText, str);
1132                                         baseCount++;
1133                                 }
1134                         }
1135                 }
1136         }
1137         
1138         if(baseCount<=1) return baseList[0];
1139         else {
1140                 baseCount = pupmenu(menuText);
1141                 
1142                 if (baseCount != -1) { /* If nothing is selected then dont do anything */
1143                         return baseList[baseCount-1];
1144                 }
1145                 else return NULL;
1146         }
1147 }
1148
1149 /* we want a select buffer with bones, if there are... */
1150 /* so check three selection levels and compare */
1151 static short mixed_bones_object_selectbuffer(unsigned int *buffer, short *mval)
1152 {
1153         int offs;
1154         short a, hits15, hits9=0, hits5=0;
1155         short has_bones15=0, has_bones9=0, has_bones5=0;
1156         
1157         hits15= view3d_opengl_select(buffer, MAXPICKBUF, mval[0]-14, mval[1]-14, mval[0]+14, mval[1]+14);
1158         if(hits15) {
1159                 for(a=0; a<hits15; a++) if(buffer[4*a+3] & 0xFFFF0000) has_bones15= 1;
1160                 
1161                 offs= 4*hits15;
1162                 hits9= view3d_opengl_select(buffer+offs, MAXPICKBUF-offs, mval[0]-9, mval[1]-9, mval[0]+9, mval[1]+9);
1163                 if(hits9) {
1164                         for(a=0; a<hits9; a++) if(buffer[offs+4*a+3] & 0xFFFF0000) has_bones9= 1;
1165                         
1166                         offs+= 4*hits9;
1167                         hits5= view3d_opengl_select(buffer+offs, MAXPICKBUF-offs, mval[0]-5, mval[1]-5, mval[0]+5, mval[1]+5);
1168                         if(hits5) {
1169                                 for(a=0; a<hits5; a++) if(buffer[offs+4*a+3] & 0xFFFF0000) has_bones5= 1;
1170                         }
1171                 }
1172                 
1173                 if(has_bones5) {
1174                         offs= 4*hits15 + 4*hits9;
1175                         memcpy(buffer, buffer+offs, 4*offs);
1176                         return hits5;
1177                 }
1178                 if(has_bones9) {
1179                         offs= 4*hits15;
1180                         memcpy(buffer, buffer+offs, 4*offs);
1181                         return hits9;
1182                 }
1183                 if(has_bones15) {
1184                         return hits15;
1185                 }
1186                 
1187                 if(hits5) {
1188                         offs= 4*hits15 + 4*hits9;
1189                         memcpy(buffer, buffer+offs, 4*offs);
1190                         return hits5;
1191                 }
1192                 if(hits9) {
1193                         offs= 4*hits15;
1194                         memcpy(buffer, buffer+offs, 4*offs);
1195                         return hits9;
1196                 }
1197                 return hits15;
1198         }
1199         
1200         return 0;
1201 }
1202
1203 void mouse_select(void)
1204 {
1205         Base *base, *startbase=NULL, *basact=NULL, *oldbasact=NULL;
1206         unsigned int buffer[MAXPICKBUF];
1207         int temp, a, dist=100;
1208         short hits, mval[2];
1209
1210         /* always start list from basact in wire mode */
1211         startbase=  FIRSTBASE;
1212         if(BASACT && BASACT->next) startbase= BASACT->next;
1213
1214         getmouseco_areawin(mval);
1215         
1216         /* This block uses the control key to make the object selected by its centre point rather then its contents */
1217         if(G.obedit==0 && (G.qual & LR_CTRLKEY)) {
1218                 
1219                 if(G.qual & LR_ALTKEY) basact= mouse_select_menu(NULL, 0, mval);
1220                 else {
1221                         base= startbase;
1222                         while(base) {
1223                                 
1224                                 if(base->lay & G.vd->lay) {
1225                                         
1226                                         project_short(base->object->obmat[3], &base->sx);
1227                                         
1228                                         temp= abs(base->sx -mval[0]) + abs(base->sy -mval[1]);
1229                                         if(base==BASACT) temp+=10;
1230                                         if(temp<dist ) {
1231                                                 
1232                                                 dist= temp;
1233                                                 basact= base;
1234                                         }
1235                                 }
1236                                 base= base->next;
1237                                 
1238                                 if(base==0) base= FIRSTBASE;
1239                                 if(base==startbase) break;
1240                         }
1241                 }
1242         }
1243         else {
1244                 /* if objects have posemode set, the bones are in the same selection buffer */
1245                 
1246                 hits= mixed_bones_object_selectbuffer(buffer, mval);
1247                 
1248                 if(hits>0) {
1249                         int has_bones= 0;
1250                         
1251                         for(a=0; a<hits; a++) if(buffer[4*a+3] & 0xFFFF0000) has_bones= 1;
1252
1253                         if(has_bones==0 && (G.qual & LR_ALTKEY)) 
1254                                 basact= mouse_select_menu(buffer, hits, mval);
1255                         else {
1256                                 static short lastmval[2]={-100, -100};
1257                                 int donearest= 0;
1258                                 
1259                                 /* define if we use solid nearest select or not */
1260                                 if(G.vd->drawtype>OB_WIRE) {
1261                                         donearest= 1;
1262                                         if( ABS(mval[0]-lastmval[0])<3 && ABS(mval[1]-lastmval[1])<3) {
1263                                                 if(!has_bones)  // hrms, if theres bones we always do nearest
1264                                                         donearest= 0;
1265                                         }
1266                                 }
1267                                 lastmval[0]= mval[0]; lastmval[1]= mval[1];
1268                                 
1269                                 if(donearest) {
1270                                         unsigned int min= 0xFFFFFFFF;
1271                                         int selcol= 0, notcol=0;
1272                                         
1273
1274                                         if(has_bones) {
1275                                                 /* we skip non-bone hits */
1276                                                 for(a=0; a<hits; a++) {
1277                                                         if( min > buffer[4*a+1] && (buffer[4*a+3] & 0xFFFF0000) ) {
1278                                                                 min= buffer[4*a+1];
1279                                                                 selcol= buffer[4*a+3] & 0xFFFF;
1280                                                         }
1281                                                 }
1282                                         }
1283                                         else {
1284                                                 /* only exclude active object when it is selected... */
1285                                                 if(BASACT && (BASACT->flag & SELECT) && hits>1) notcol= BASACT->selcol; 
1286                                         
1287                                                 for(a=0; a<hits; a++) {
1288                                                         if( min > buffer[4*a+1] && notcol!=(buffer[4*a+3] & 0xFFFF)) {
1289                                                                 min= buffer[4*a+1];
1290                                                                 selcol= buffer[4*a+3] & 0xFFFF;
1291                                                         }
1292                                                 }
1293                                         }
1294
1295                                         base= FIRSTBASE;
1296                                         while(base) {
1297                                                 if(base->lay & G.vd->lay) {
1298                                                         if(base->selcol==selcol) break;
1299                                                 }
1300                                                 base= base->next;
1301                                         }
1302                                         if(base) basact= base;
1303                                 }
1304                                 else {
1305                                         
1306                                         base= startbase;
1307                                         while(base) {
1308                                                 if(base->lay & G.vd->lay) {
1309                                                         for(a=0; a<hits; a++) {
1310                                                                 if(has_bones) {
1311                                                                         /* skip non-bone objects */
1312                                                                         if((buffer[4*a+3] & 0xFFFF0000)) {
1313                                                                                 if(base->selcol== (buffer[(4*a)+3] & 0xFFFF))
1314                                                                                         basact= base;
1315                                                                         }
1316                                                                 }
1317                                                                 else {
1318                                                                         if(base->selcol== (buffer[(4*a)+3] & 0xFFFF))
1319                                                                                 basact= base;
1320                                                                 }
1321                                                         }
1322                                                 }
1323                                                 
1324                                                 if(basact) break;
1325                                                 
1326                                                 base= base->next;
1327                                                 if(base==NULL) base= FIRSTBASE;
1328                                                 if(base==startbase) break;
1329                                         }
1330                                 }
1331                         }
1332                         
1333                         if(has_bones && basact) {
1334                                 if( do_pose_selectbuffer(basact, buffer, hits) ) {      // then bone is found
1335                                 
1336                                         /* in weightpaint, we use selected bone to select vertexgroup, so no switch to new active object */
1337                                         if(G.f & G_WEIGHTPAINT) {
1338                                                 /* we make the armature selected */
1339                                                 basact->flag|= SELECT;
1340                                                 basact->object->flag= basact->flag;
1341                                                 /* prevent activating */
1342                                                 basact= NULL;
1343                                         }
1344                                 }
1345                                 /* prevent bone selecting to pass on to object selecting */
1346                                 if(basact==BASACT)
1347                                         basact= NULL;
1348                         }
1349                 }
1350         }
1351         
1352         /* so, do we have something selected? */
1353         if(basact) {
1354                 
1355                 if(G.obedit) {
1356                         /* only do select */
1357                         deselectall_except(basact);
1358                         basact->flag |= SELECT;
1359                 }
1360                 else {
1361                         oldbasact= BASACT;
1362                         BASACT= basact;
1363                         
1364                         if((G.qual & LR_SHIFTKEY)==0) {
1365                                 deselectall_except(basact);
1366                                 basact->flag |= SELECT;
1367                         }
1368                         else if(G.qual==(LR_SHIFTKEY|LR_ALTKEY)) {
1369                                 select_all_from_groups(basact);
1370                         }
1371                         else {
1372                                 if(basact->flag & SELECT) {
1373                                         if(basact==oldbasact)
1374                                                 basact->flag &= ~SELECT;
1375                                 }
1376                                 else basact->flag |= SELECT;
1377                         }
1378
1379                         // copy
1380                         basact->object->flag= basact->flag;
1381                         
1382                         if(oldbasact != basact) {
1383                                 set_active_base(basact);
1384                         }
1385
1386                         // for visual speed, only in wire mode
1387                         if(G.vd->drawtype==OB_WIRE) {
1388                                 /* however, not for posemodes */
1389                                 if(basact->object->flag & OB_POSEMODE);
1390                                 else if(oldbasact && (oldbasact->object->flag & OB_POSEMODE));
1391                                 else {
1392                                         if(oldbasact && oldbasact != basact && (oldbasact->lay & G.vd->lay)) 
1393                                                 draw_object_ext(oldbasact);
1394                                         draw_object_ext(basact);
1395                                 }
1396                         }
1397                         
1398                         /* selecting a non-mesh, should end a couple of modes... */
1399                         if(basact->object->type!=OB_MESH) {
1400                                 if(G.f & G_WEIGHTPAINT) {
1401                                         set_wpaint();   /* toggle */
1402                                 }
1403                                 if(G.f & G_VERTEXPAINT) {
1404                                         set_vpaint();   /* toggle */
1405                                 }
1406                                 if(G.f & G_FACESELECT) {
1407                                         set_faceselect();       /* toggle */
1408                                 }
1409                         }
1410                         
1411                         allqueue(REDRAWBUTSLOGIC, 0);
1412                         allqueue(REDRAWDATASELECT, 0);
1413                         allqueue(REDRAWBUTSOBJECT, 0);
1414                         allqueue(REDRAWACTION, 0);
1415                         allqueue(REDRAWNLA, 0);
1416                         allqueue(REDRAWTIME, 0);
1417                         allqueue(REDRAWHEADERS, 0);     /* To force display update for the posebutton */
1418                 }
1419                 /* also because multiple 3d windows can be open */
1420                 allqueue(REDRAWVIEW3D, 0);
1421                 
1422         }
1423
1424         countall();
1425
1426         rightmouse_transform(); // does undo push!
1427 }
1428
1429 /* ------------------------------------------------------------------------- */
1430
1431 static int edge_inside_circle(short centx, short centy, short rad, short x1, short y1, short x2, short y2)
1432 {
1433         int radsq= rad*rad;
1434         float v1[2], v2[2], v3[2];
1435         
1436         // check points in circle itself
1437         if( (x1-centx)*(x1-centx) + (y1-centy)*(y1-centy) <= radsq ) return 1;
1438         if( (x2-centx)*(x2-centx) + (y2-centy)*(y2-centy) <= radsq ) return 1;
1439         
1440         // pointdistline
1441         v3[0]= centx;
1442         v3[1]= centy;
1443         v1[0]= x1;
1444         v1[1]= y1;
1445         v2[0]= x2;
1446         v2[1]= y2;
1447         
1448         if( PdistVL2Dfl(v3, v1, v2) < (float)rad ) return 1;
1449         
1450         return 0;
1451 }
1452
1453 static void do_nurbs_box_select__doSelect(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y)
1454 {
1455         struct { rcti *rect; int select; } *data = userData;
1456
1457         if (BLI_in_rcti(data->rect, x, y)) {
1458                 if (bp) {
1459                         bp->f1 = data->select?(bp->f1|1):(bp->f1&~1);
1460                 } else {
1461                         if (beztindex==0) {
1462                                 bezt->f1 = data->select?(bezt->f1|1):(bezt->f1&~1);
1463                         } else if (beztindex==1) {
1464                                 bezt->f2 = data->select?(bezt->f2|1):(bezt->f2&~1);
1465                         } else {
1466                                 bezt->f3 = data->select?(bezt->f3|1):(bezt->f3&~1);
1467                         }
1468                 }
1469         }
1470 }
1471 static void do_nurbs_box_select(rcti *rect, int select)
1472 {
1473         struct { rcti *rect; int select; } data;
1474
1475         data.rect = rect;
1476         data.select = select;
1477
1478         nurbs_foreachScreenVert(do_nurbs_box_select__doSelect, &data);
1479 }
1480
1481 static void do_lattice_box_select__doSelect(void *userData, BPoint *bp, int x, int y)
1482 {
1483         struct { rcti *rect; int select; } *data = userData;
1484
1485         if (BLI_in_rcti(data->rect, x, y)) {
1486                 bp->f1 = data->select?(bp->f1|1):(bp->f1&~1);
1487         }
1488 }
1489 static void do_lattice_box_select(rcti *rect, int select)
1490 {
1491         struct { rcti *rect; int select, pass, done; } data;
1492
1493         data.rect = rect;
1494         data.select = select;
1495
1496         lattice_foreachScreenVert(do_lattice_box_select__doSelect, &data);
1497 }
1498
1499 static void do_mesh_box_select__doSelectVert(void *userData, EditVert *eve, int x, int y, int index)
1500 {
1501         struct { rcti *rect; short select, pass, done; } *data = userData;
1502
1503         if (BLI_in_rcti(data->rect, x, y)) {
1504                 eve->f = data->select?(eve->f|1):(eve->f&~1);
1505         }
1506 }
1507 static void do_mesh_box_select__doSelectEdge(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index)
1508 {
1509         struct { rcti *rect; short select, pass, done; } *data = userData;
1510
1511         if(EM_check_backbuf(em_solidoffs+index)) {
1512                 if (data->pass==0) {
1513                         if (edge_fully_inside_rect(data->rect, x0, y0, x1, y1)) {
1514                                 EM_select_edge(eed, data->select);
1515                                 data->done = 1;
1516                         }
1517                 } else {
1518                         if (edge_inside_rect(data->rect, x0, y0, x1, y1)) {
1519                                 EM_select_edge(eed, data->select);
1520                         }
1521                 }
1522         }
1523 }
1524 static void do_mesh_box_select__doSelectFace(void *userData, EditFace *efa, int x, int y, int index)
1525 {
1526         struct { rcti *rect; short select, pass, done; } *data = userData;
1527
1528         if (BLI_in_rcti(data->rect, x, y)) {
1529                 EM_select_face_fgon(efa, data->select);
1530         }
1531 }
1532 static void do_mesh_box_select(rcti *rect, int select)
1533 {
1534         struct { rcti *rect; short select, pass, done; } data;
1535         EditMesh *em = G.editMesh;
1536         int bbsel;
1537         
1538         data.rect = rect;
1539         data.select = select;
1540         data.pass = 0;
1541         data.done = 0;
1542
1543         bbsel= EM_init_backbuf_border(rect->xmin, rect->ymin, rect->xmax, rect->ymax);
1544
1545         if(G.scene->selectmode & SCE_SELECT_VERTEX) {
1546                 if (bbsel) {
1547                         EM_backbuf_checkAndSelectVerts(em, select);
1548                 } else {
1549                         mesh_foreachScreenVert(do_mesh_box_select__doSelectVert, &data, 1);
1550                 }
1551         }
1552         if(G.scene->selectmode & SCE_SELECT_EDGE) {
1553                         /* Does both bbsel and non-bbsel versions (need screen cos for both) */
1554
1555                 data.pass = 0;
1556                 mesh_foreachScreenEdge(do_mesh_box_select__doSelectEdge, &data, 0);
1557
1558                 if (data.done==0) {
1559                         data.pass = 1;
1560                         mesh_foreachScreenEdge(do_mesh_box_select__doSelectEdge, &data, 0);
1561                 }
1562         }
1563         
1564         if(G.scene->selectmode & SCE_SELECT_FACE) {
1565                 if(bbsel) {
1566                         EM_backbuf_checkAndSelectFaces(em, select);
1567                 } else {
1568                         mesh_foreachScreenFace(do_mesh_box_select__doSelectFace, &data);
1569                 }
1570         }
1571         
1572         EM_free_backbuf();
1573                 
1574         EM_selectmode_flush();
1575 }
1576
1577 /**
1578  * Does the 'borderselect' command. (Select verts based on selecting with a 
1579  * border: key 'b'). All selecting seems to be done in the get_border part.
1580  */
1581 void borderselect(void)
1582 {
1583         rcti rect;
1584         Base *base;
1585         MetaElem *ml;
1586         unsigned int buffer[MAXPICKBUF];
1587         int a, index;
1588         short hits, val;
1589
1590         if(G.obedit==NULL && (G.f & G_FACESELECT)) {
1591                 face_borderselect();
1592                 return;
1593         }
1594         
1595         setlinestyle(2);
1596         val= get_border(&rect, 3);
1597         setlinestyle(0);
1598         
1599         if(val==0)
1600                 return;
1601         
1602         if(G.obedit) {
1603                 if(G.obedit->type==OB_MESH) {
1604                         do_mesh_box_select(&rect, (val==LEFTMOUSE));
1605                         allqueue(REDRAWVIEW3D, 0);
1606                 }
1607                 else if ELEM(G.obedit->type, OB_CURVE, OB_SURF) {
1608                         do_nurbs_box_select(&rect, val==LEFTMOUSE);
1609                         allqueue(REDRAWVIEW3D, 0);
1610                 }
1611                 else if(G.obedit->type==OB_MBALL) {
1612                         hits= view3d_opengl_select(buffer, MAXPICKBUF, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
1613                         
1614                         ml= editelems.first;
1615                         
1616                         while(ml) {
1617                                 for(a=0; a<hits; a++) {
1618                                         if(ml->selcol1==buffer[ (4 * a) + 3 ]) {
1619                                                 ml->flag |= MB_SCALE_RAD;
1620                                                 if(val==LEFTMOUSE) ml->flag |= SELECT;
1621                                                 else ml->flag &= ~SELECT;
1622                                                 break;
1623                                         }
1624                                         if(ml->selcol2==buffer[ (4 * a) + 3 ]) {
1625                                                 ml->flag &= ~MB_SCALE_RAD;
1626                                                 if(val==LEFTMOUSE) ml->flag |= SELECT;
1627                                                 else ml->flag &= ~SELECT;
1628                                                 break;
1629                                         }
1630                                 }
1631                                 ml= ml->next;
1632                         }
1633                         allqueue(REDRAWVIEW3D, 0);
1634                 }
1635                 else if(G.obedit->type==OB_ARMATURE) {
1636                         EditBone *ebone;
1637                         
1638                         /* clear flag we use to detect point was affected */
1639                         for(ebone= G.edbo.first; ebone; ebone= ebone->next)
1640                                 ebone->flag &= ~BONE_DONE;
1641                         
1642                         hits= view3d_opengl_select(buffer, MAXPICKBUF, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
1643                         
1644                         /* first we only check points inside the border */
1645                         for (a=0; a<hits; a++){
1646                                 index = buffer[(4*a)+3];
1647                                 if (index!=-1) {
1648                                         ebone = BLI_findlink(&G.edbo, index & ~(BONESEL_ANY));
1649                                         if (index & BONESEL_TIP) {
1650                                                 ebone->flag |= BONE_DONE;
1651                                                 if (val==LEFTMOUSE) ebone->flag |= BONE_TIPSEL;
1652                                                 else ebone->flag &= ~BONE_TIPSEL;
1653                                         }
1654                                         
1655                                         if (index & BONESEL_ROOT) {
1656                                                 ebone->flag |= BONE_DONE;
1657                                                 if (val==LEFTMOUSE) ebone->flag |= BONE_ROOTSEL;
1658                                                 else ebone->flag &= ~BONE_ROOTSEL;
1659                                         }
1660                                 }
1661                         }
1662                         
1663                         /* now we have to flush tag from parents... */
1664                         for(ebone= G.edbo.first; ebone; ebone= ebone->next) {
1665                                 if(ebone->parent && (ebone->flag & BONE_CONNECTED)) {
1666                                         if(ebone->parent->flag & BONE_DONE)
1667                                                 ebone->flag |= BONE_DONE;
1668                                 }
1669                         }
1670                         
1671                         /* only select/deselect entire bones when no points where in the rect */
1672                         for (a=0; a<hits; a++){
1673                                 index = buffer[(4*a)+3];
1674                                 if (index!=-1) {
1675                                         ebone = BLI_findlink(&G.edbo, index & ~(BONESEL_ANY));
1676                                         if (index & BONESEL_BONE) {
1677                                                 if(!(ebone->flag & BONE_DONE)) {
1678                                                         if (val==LEFTMOUSE)
1679                                                                 ebone->flag |= (BONE_ROOTSEL|BONE_TIPSEL|BONE_SELECTED);
1680                                                         else
1681                                                                 ebone->flag &= ~(BONE_ROOTSEL|BONE_TIPSEL|BONE_SELECTED);
1682                                                 }
1683                                         }
1684                                 }
1685                         }
1686                         
1687                         allqueue(REDRAWBUTSEDIT, 0);
1688                         allqueue(REDRAWBUTSOBJECT, 0);
1689                         allqueue(REDRAWACTION, 0);
1690                         allqueue(REDRAWVIEW3D, 0);
1691                 }
1692                 else if(G.obedit->type==OB_LATTICE) {
1693                         do_lattice_box_select(&rect, val==LEFTMOUSE);
1694                         allqueue(REDRAWVIEW3D, 0);
1695                 }
1696         }
1697         else {  // no editmode, unified for bones and objects
1698                 Bone *bone;
1699                 unsigned int *vbuffer=NULL; /* selection buffer */
1700                 unsigned int *col;                      /* color in buffer      */
1701                 short selecting = 0;
1702
1703                 if (val==LEFTMOUSE)
1704                         selecting = 1;
1705                 
1706                 /* selection buffer now has bones potentially too, so we add MAXPICKBUF */
1707                 vbuffer = MEM_mallocN(4 * (G.totobj+MAXPICKBUF) * sizeof(unsigned int), "selection buffer");
1708                 hits= view3d_opengl_select(vbuffer, 4*(G.totobj+MAXPICKBUF), rect.xmin, rect.ymin, rect.xmax, rect.ymax);
1709                 /*
1710                 LOGIC NOTES (theeth):
1711                 The buffer and ListBase have the same relative order, which makes the selection
1712                 very simple. Loop through both data sets at the same time, if the color
1713                 is the same as the object, we have a hit and can move to the next color
1714                 and object pair, if not, just move to the next object,
1715                 keeping the same color until we have a hit.
1716
1717                 The buffer order is defined by OGL standard, hopefully no stupid GFX card
1718                 does it incorrectly.
1719                 */
1720
1721                 if (hits) { /* no need to loop if there's no hit */
1722                         base= FIRSTBASE;
1723                         col = vbuffer + 3;
1724                         while(base && hits) {
1725                                 Base *next = base->next;
1726                                 if(base->lay & G.vd->lay) {
1727                                         while (base->selcol == (*col & 0xFFFF)) {       // we got an object
1728                                                 
1729                                                 if(*col & 0xFFFF0000) {                                 // we got a bone
1730                                                         bone = get_indexed_bone(base->object, *col & ~(BONESEL_ANY));
1731                                                         if(bone) {
1732                                                                 if(selecting) {
1733                                                                         bone->flag |= BONE_SELECTED;
1734                                                                         select_actionchannel_by_name(base->object->action, bone->name, 1);
1735                                                                 }
1736                                                                 else {
1737                                                                         bone->flag &= ~(BONE_ACTIVE|BONE_SELECTED);
1738                                                                         select_actionchannel_by_name(base->object->action, bone->name, 0);
1739                                                                 }
1740                                                         }
1741                                                 }
1742                                                 else {
1743                                                         if (selecting)
1744                                                                 base->flag |= SELECT;
1745                                                         else
1746                                                                 base->flag &= ~SELECT;
1747
1748                                                         base->object->flag= base->flag;
1749                                                 }
1750
1751                                                 col+=4; /* next color */
1752                                                 hits--;
1753                                                 if(hits==0) break;
1754                                         }
1755                                 }
1756                                 
1757                                 base= next;
1758                         }
1759                 }
1760                 /* frontbuffer flush */
1761                 glFlush();
1762
1763                 MEM_freeN(vbuffer);
1764                 
1765                 allqueue(REDRAWDATASELECT, 0);
1766                 allqueue(REDRAWBUTSLOGIC, 0);
1767                 allqueue(REDRAWNLA, 0);
1768         }
1769
1770         countall();
1771         
1772         allqueue(REDRAWBUTSOBJECT, 0);
1773         allqueue(REDRAWVIEW3D, 0);
1774         allqueue(REDRAWINFO, 0);
1775
1776         BIF_undo_push("Border select");
1777         
1778 } /* end of borderselect() */
1779
1780 /* ------------------------------------------------------------------------- */
1781
1782 /** The following functions are quick & dirty callback functions called
1783   * on the Circle select function (press B twice in Editmode)
1784   * They were torn out of the circle_select to make the latter more reusable
1785   * The callback version of circle_select (called circle_selectCB) was moved
1786   * to edit.c because of it's (wanted) generality.
1787
1788         XXX These callback functions are still dirty, because they call globals... 
1789   */
1790
1791 static void mesh_selectionCB__doSelectVert(void *userData, EditVert *eve, int x, int y, int index)
1792 {
1793         struct { short select, mval[2]; float radius; } *data = userData;
1794         int mx = x - data->mval[0], my = y - data->mval[1];
1795         float r = sqrt(mx*mx + my*my);
1796
1797         if (r<=data->radius) {
1798                 eve->f = data->select?(eve->f|1):(eve->f&~1);
1799         }
1800 }
1801 static void mesh_selectionCB__doSelectEdge(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index)
1802 {
1803         struct { short select, mval[2]; float radius; } *data = userData;
1804
1805         if (edge_inside_circle(data->mval[0], data->mval[1], (short) data->radius, x0, y0, x1, y1)) {
1806                 EM_select_edge(eed, data->select);
1807         }
1808 }
1809 static void mesh_selectionCB__doSelectFace(void *userData, EditFace *efa, int x, int y, int index)
1810 {
1811         struct { short select, mval[2]; float radius; } *data = userData;
1812         int mx = x - data->mval[0], my = y - data->mval[1];
1813         float r = sqrt(mx*mx + my*my);
1814
1815         if (r<=data->radius) {
1816                 EM_select_face_fgon(efa, data->select);
1817         }
1818 }
1819 static void mesh_selectionCB(int selecting, Object *editobj, short *mval, float rad)
1820 {
1821         struct { short select, mval[2]; float radius; } data;
1822         EditMesh *em = G.editMesh;
1823         int bbsel;
1824
1825         if(!G.obedit && (G.f&G_FACESELECT)) {
1826                 Mesh *me = get_mesh(OBACT);
1827
1828                 if (me) {
1829                         em_vertoffs= me->totface+1;     // max index array
1830
1831                         bbsel= EM_init_backbuf_circle(mval[0], mval[1], (short)(rad+1.0));
1832                         EM_backbuf_checkAndSelectTFaces(me, selecting==LEFTMOUSE);
1833                         EM_free_backbuf();
1834
1835                         object_tface_flags_changed(OBACT, 0);
1836                 }
1837
1838                 return;
1839         }
1840
1841         bbsel= EM_init_backbuf_circle(mval[0], mval[1], (short)(rad+1.0));
1842         
1843         data.select = (selecting==LEFTMOUSE);
1844         data.mval[0] = mval[0];
1845         data.mval[1] = mval[1];
1846         data.radius = rad;
1847
1848         if(G.scene->selectmode & SCE_SELECT_VERTEX) {
1849                 if(bbsel) {
1850                         EM_backbuf_checkAndSelectVerts(em, selecting==LEFTMOUSE);
1851                 } else {
1852                         mesh_foreachScreenVert(mesh_selectionCB__doSelectVert, &data, 1);
1853                 }
1854         }
1855
1856         if(G.scene->selectmode & SCE_SELECT_EDGE) {
1857                 if (bbsel) {
1858                         EM_backbuf_checkAndSelectEdges(em, selecting==LEFTMOUSE);
1859                 } else {
1860                         mesh_foreachScreenEdge(mesh_selectionCB__doSelectEdge, &data, 0);
1861                 }
1862         }
1863         
1864         if(G.scene->selectmode & SCE_SELECT_FACE) {
1865                 if(bbsel) {
1866                         EM_backbuf_checkAndSelectFaces(em, selecting==LEFTMOUSE);
1867                 } else {
1868                         mesh_foreachScreenFace(mesh_selectionCB__doSelectFace, &data);
1869                 }
1870         }
1871
1872         EM_free_backbuf();
1873         EM_selectmode_flush();
1874 }
1875
1876
1877 static void nurbscurve_selectionCB__doSelect(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y)
1878 {
1879         struct { short select, mval[2]; float radius; } *data = userData;
1880         int mx = x - data->mval[0], my = y - data->mval[1];
1881         float r = sqrt(mx*mx + my*my);
1882
1883         if (r<=data->radius) {
1884                 if (bp) {
1885                         bp->f1 = data->select?(bp->f1|1):(bp->f1&~1);
1886                 } else {
1887                         if (beztindex==0) {
1888                                 bezt->f1 = data->select?(bezt->f1|1):(bezt->f1&~1);
1889                         } else if (beztindex==1) {
1890                                 bezt->f2 = data->select?(bezt->f2|1):(bezt->f2&~1);
1891                         } else {
1892                                 bezt->f3 = data->select?(bezt->f3|1):(bezt->f3&~1);
1893                         }
1894                 }
1895         }
1896 }
1897 static void nurbscurve_selectionCB(int selecting, Object *editobj, short *mval, float rad)
1898 {
1899         struct { short select, mval[2]; float radius; } data;
1900
1901         data.select = (selecting==LEFTMOUSE);
1902         data.mval[0] = mval[0];
1903         data.mval[1] = mval[1];
1904         data.radius = rad;
1905
1906         nurbs_foreachScreenVert(nurbscurve_selectionCB__doSelect, &data);
1907 }
1908
1909
1910 static void latticecurve_selectionCB__doSelect(void *userData, BPoint *bp, int x, int y)
1911 {
1912         struct { short select, mval[2]; float radius; } *data = userData;
1913         int mx = x - data->mval[0], my = y - data->mval[1];
1914         float r = sqrt(mx*mx + my*my);
1915
1916         if (r<=data->radius) {
1917                 bp->f1 = data->select?(bp->f1|1):(bp->f1&~1);
1918         }
1919 }
1920 static void lattice_selectionCB(int selecting, Object *editobj, short *mval, float rad)
1921 {
1922         struct { short select, mval[2]; float radius; } data;
1923
1924         data.select = (selecting==LEFTMOUSE);
1925         data.mval[0] = mval[0];
1926         data.mval[1] = mval[1];
1927         data.radius = rad;
1928
1929         lattice_foreachScreenVert(latticecurve_selectionCB__doSelect, &data);
1930 }
1931
1932 /** Callbacks for selection in Editmode */
1933
1934 void obedit_selectionCB(short selecting, Object *editobj, short *mval, float rad) 
1935 {
1936         switch(editobj->type) {         
1937         case OB_MESH:
1938                 mesh_selectionCB(selecting, editobj, mval, rad);
1939                 break;
1940         case OB_CURVE:
1941         case OB_SURF:
1942                 nurbscurve_selectionCB(selecting, editobj, mval, rad);
1943                 break;
1944         case OB_LATTICE:
1945                 lattice_selectionCB(selecting, editobj, mval, rad);
1946                 break;
1947         default:
1948                 return;
1949         }
1950
1951         draw_sel_circle(0, 0, 0, 0, 0); /* signal */
1952         force_draw(0);
1953 }
1954
1955 void set_render_border(void)
1956 {
1957         rcti rect;
1958         short val;
1959
1960         if(G.vd->persp!=2) return;
1961         
1962         val= get_border(&rect, 3);
1963         if(val) {
1964                 rcti vb;
1965
1966                 calc_viewborder(G.vd, &vb);
1967
1968                 G.scene->r.border.xmin= (float) (rect.xmin-vb.xmin)/(vb.xmax-vb.xmin);
1969                 G.scene->r.border.ymin= (float) (rect.ymin-vb.ymin)/(vb.ymax-vb.ymin);
1970                 G.scene->r.border.xmax= (float) (rect.xmax-vb.xmin)/(vb.xmax-vb.xmin);
1971                 G.scene->r.border.ymax= (float) (rect.ymax-vb.ymin)/(vb.ymax-vb.ymin);
1972                 
1973                 CLAMP(G.scene->r.border.xmin, 0.0, 1.0);
1974                 CLAMP(G.scene->r.border.ymin, 0.0, 1.0);
1975                 CLAMP(G.scene->r.border.xmax, 0.0, 1.0);
1976                 CLAMP(G.scene->r.border.ymax, 0.0, 1.0);
1977                 
1978                 allqueue(REDRAWVIEWCAM, 1);
1979                 // if it was not set, we do this
1980                 G.scene->r.mode |= R_BORDER;
1981                 allqueue(REDRAWBUTSSCENE, 1);
1982         }
1983 }
1984
1985
1986
1987 void fly(void)
1988 {
1989         float speed=0.0, speedo=1.0, zspeed=0.0, dvec[3], *quat, mat[3][3];
1990         float oldvec[3], oldrot[3];
1991         int loop=1;
1992         unsigned short toets;
1993         short val, cent[2];
1994         short mval[2];
1995         
1996         if(curarea->spacetype!=SPACE_VIEW3D) return;
1997         if(G.vd->camera == 0) return;
1998         if(G.vd->persp<2) return;
1999         
2000         VECCOPY(oldvec, G.vd->camera->loc);
2001         VECCOPY(oldrot, G.vd->camera->rot);
2002         
2003         cent[0]= curarea->winrct.xmin+(curarea->winx)/2;
2004         cent[1]= curarea->winrct.ymin+(curarea->winy)/2;
2005         
2006         warp_pointer(cent[0], cent[1]);
2007         
2008         /* we have to rely on events to give proper mousecoords after a warp_pointer */
2009         mval[0]= cent[0]=  (curarea->winx)/2;
2010         mval[1]= cent[1]=  (curarea->winy)/2;
2011         
2012         headerprint("Fly");
2013         
2014         while(loop) {
2015                 
2016
2017                 while(qtest()) {
2018                         
2019                         toets= extern_qread(&val);
2020                         
2021                         if(val) {
2022                                 if(toets==MOUSEY) getmouseco_areawin(mval);
2023                                 else if(toets==ESCKEY) {
2024                                         VECCOPY(G.vd->camera->loc, oldvec);
2025                                         VECCOPY(G.vd->camera->rot, oldrot);
2026                                         loop= 0;
2027                                         break;
2028                                 }
2029                                 else if(toets==SPACEKEY) {
2030                                         loop= 0;
2031                                         BIF_undo_push("Fly camera");
2032                                         break;
2033                                 }
2034                                 else if(toets==LEFTMOUSE) {
2035                                         speed+= G.vd->grid/75.0;
2036                                         if(get_mbut()&M_MOUSE) speed= 0.0;
2037                                 }
2038                                 else if(toets==MIDDLEMOUSE) {
2039                                         speed-= G.vd->grid/75.0;
2040                                         if(get_mbut()&L_MOUSE) speed= 0.0;
2041                                 }
2042                         }
2043                 }
2044                 if(loop==0) break;
2045                 
2046                 /* define dvec */
2047                 val= mval[0]-cent[0];
2048                 if(val>20) val-= 20; else if(val< -20) val+= 20; else val= 0;
2049                 dvec[0]= 0.000001*val*val;
2050                 if(val>0) dvec[0]= -dvec[0];
2051                 
2052                 val= mval[1]-cent[1];
2053                 if(val>20) val-= 20; else if(val< -20) val+= 20; else val= 0;
2054                 dvec[1]= 0.000001*val*val;
2055                 if(val>0) dvec[1]= -dvec[1];
2056                 
2057                 dvec[2]= 1.0;
2058                 
2059                 zspeed= 0.0;
2060                 if(get_qual()&LR_CTRLKEY) zspeed= -G.vd->grid/25.0;
2061                 if(get_qual()&LR_ALTKEY) zspeed= G.vd->grid/25.0;
2062                 
2063                 if(speedo!=0.0 || zspeed!=0.0 || dvec[0]!=0.0 || dvec[1]!=0.0) {
2064                 
2065                         Normalise(dvec);
2066                         
2067                         Mat3CpyMat4(mat, G.vd->viewinv);
2068                         Mat3MulVecfl(mat, dvec);
2069                         quat= vectoquat(dvec, 5, 1);    /* track and upflag, not from the base: camera view calculation does not use that */
2070                         
2071                         QuatToEul(quat, G.vd->camera->rot);
2072                         
2073                         compatible_eul(G.vd->camera->rot, oldrot);
2074                         
2075                         VecMulf(dvec, speed);
2076                         G.vd->camera->loc[0]-= dvec[0];
2077                         G.vd->camera->loc[1]-= dvec[1];
2078                         G.vd->camera->loc[2]-= (dvec[2]-zspeed);
2079                         
2080                         scrarea_do_windraw(curarea);
2081                         screen_swapbuffers();
2082                 }
2083                 speedo= speed;
2084         }
2085         
2086         allqueue(REDRAWVIEW3D, 0);
2087         scrarea_queue_headredraw(curarea);
2088         
2089 }
2090
2091 void view3d_edit_clipping(View3D *v3d)
2092 {
2093         
2094         if(v3d->flag & V3D_CLIPPING) {
2095                 v3d->flag &= ~V3D_CLIPPING;
2096                 scrarea_queue_winredraw(curarea);
2097                 if(v3d->clipbb) MEM_freeN(v3d->clipbb);
2098                 v3d->clipbb= NULL;
2099         }
2100         else {
2101                 rcti rect;
2102                 double mvmatrix[16];
2103                 double projmatrix[16];
2104                 double xs, ys, p[3];
2105                 GLint viewport[4];
2106                 short val;
2107                 
2108                 /* get border in window coords */
2109                 setlinestyle(2);
2110                 val= get_border(&rect, 3);
2111                 setlinestyle(0);
2112                 if(val==0) return;
2113                 
2114                 v3d->flag |= V3D_CLIPPING;
2115                 v3d->clipbb= MEM_mallocN(sizeof(BoundBox), "clipbb");
2116                 
2117                 /* convert border to 3d coordinates */
2118                 
2119                 /* Get the matrices needed for gluUnProject */
2120                 glGetIntegerv(GL_VIEWPORT, viewport);
2121                 glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix);
2122                 glGetDoublev(GL_PROJECTION_MATRIX, projmatrix);
2123                 
2124                 /* Set up viewport so that gluUnProject will give correct values */
2125                 viewport[0] = 0;
2126                 viewport[1] = 0;
2127                 
2128                 /* four clipping planes and bounding volume */
2129                 /* first do the bounding volume */
2130                 for(val=0; val<4; val++) {
2131                         
2132                         xs= (val==0||val==3)?rect.xmin:rect.xmax;
2133                         ys= (val==0||val==1)?rect.ymin:rect.ymax;
2134                         
2135                         gluUnProject(xs, ys, 0.0, mvmatrix, projmatrix, viewport, &p[0], &p[1], &p[2]);
2136                         VECCOPY(v3d->clipbb->vec[val], p);
2137                         
2138                         gluUnProject(xs, ys, 1.0, mvmatrix, projmatrix, viewport, &p[0], &p[1], &p[2]);
2139                         VECCOPY(v3d->clipbb->vec[4+val], p);
2140                 }
2141                 
2142                 /* then plane equations */
2143                 for(val=0; val<4; val++) {
2144                         
2145                         CalcNormFloat(v3d->clipbb->vec[val], v3d->clipbb->vec[val==3?0:val+1], v3d->clipbb->vec[val+4],
2146                                                   v3d->clip[val]); 
2147                         
2148                         v3d->clip[val][3]= - v3d->clip[val][0]*v3d->clipbb->vec[val][0] 
2149                                                            - v3d->clip[val][1]*v3d->clipbb->vec[val][1] 
2150                                                            - v3d->clip[val][2]*v3d->clipbb->vec[val][2];
2151                 }
2152         }
2153 }
2154