Two in one:
[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_camera_types.h"
51 #include "DNA_group_types.h"
52 #include "DNA_lattice_types.h"
53 #include "DNA_meta_types.h"
54 #include "DNA_mesh_types.h"
55 #include "DNA_meshdata_types.h"
56 #include "DNA_object_types.h"
57 #include "DNA_scene_types.h"
58 #include "DNA_screen_types.h"
59 #include "DNA_space_types.h"
60 #include "DNA_view3d_types.h"
61 #include "DNA_userdef_types.h"
62 #include "DNA_ipo_types.h" /* for fly mode recording */
63
64 #include "BLI_blenlib.h"
65 #include "BLI_arithb.h"
66 #include "BLI_editVert.h"
67
68 #include "BKE_armature.h"
69 #include "BKE_depsgraph.h"
70 #include "BKE_global.h"
71 #include "BKE_group.h"
72 #include "BKE_lattice.h"
73 #include "BKE_main.h"
74 #include "BKE_mesh.h"
75 #include "BKE_object.h" /* fly mode where_is_object to get camera location */
76 #include "BKE_utildefines.h"
77
78 #include "BIF_butspace.h"
79 #include "BIF_editaction.h"
80 #include "BIF_editarmature.h"
81 #include "BIF_editgroup.h"
82 #include "BIF_editmesh.h"
83 #include "BIF_editoops.h"
84 #include "BIF_editsima.h"
85 #include "BIF_editview.h"
86 #include "BIF_gl.h"
87 #include "BIF_glutil.h"
88 #include "BIF_interface.h"
89 #include "BIF_mywindow.h"
90 #include "BIF_previewrender.h" /* use only so fly mode can preview when its done */
91 #include "BIF_space.h"
92 #include "BIF_screen.h"
93 #include "BIF_toolbox.h"
94
95 #include "BDR_editobject.h"     /* For headerprint */
96 #include "BDR_sculptmode.h"
97 #include "BDR_vpaint.h"
98 #include "BDR_editface.h"
99 #include "BDR_drawobject.h"
100 #include "BDR_editcurve.h"
101
102 #include "BSE_edit.h"
103 #include "BSE_view.h"           /* give_cursor() */
104 #include "BSE_editipo.h"
105 #include "BSE_drawview.h"
106
107 #include "editmesh.h"   /* borderselect uses it... */
108 #include "blendef.h"
109 #include "mydevice.h"
110
111 #include "BIF_transform.h"
112 #include "BIF_toets.h"                      /* persptoetsen                 */
113
114 extern ListBase editNurb; /* originally from exports.h, memory from editcurve.c*/
115 /* editmball.c */
116 extern ListBase editelems;
117
118 /* fly mode ises this */
119 extern void setcameratoview3d(void);
120
121 /* local prototypes */
122
123 void EM_backbuf_checkAndSelectVerts(EditMesh *em, int select)
124 {
125         EditVert *eve;
126         int index= em_wireoffs;
127
128         for(eve= em->verts.first; eve; eve= eve->next, index++) {
129                 if(eve->h==0) {
130                         if(EM_check_backbuf(index)) {
131                                 eve->f = select?(eve->f|1):(eve->f&~1);
132                         }
133                 }
134         }
135 }
136
137 void EM_backbuf_checkAndSelectEdges(EditMesh *em, int select)
138 {
139         EditEdge *eed;
140         int index= em_solidoffs;
141
142         for(eed= em->edges.first; eed; eed= eed->next, index++) {
143                 if(eed->h==0) {
144                         if(EM_check_backbuf(index)) {
145                                 EM_select_edge(eed, select);
146                         }
147                 }
148         }
149 }
150
151 void EM_backbuf_checkAndSelectFaces(EditMesh *em, int select)
152 {
153         EditFace *efa;
154         int index= 1;
155
156         for(efa= em->faces.first; efa; efa= efa->next, index++) {
157                 if(efa->h==0) {
158                         if(EM_check_backbuf(index)) {
159                                 EM_select_face_fgon(efa, select);
160                         }
161                 }
162         }
163 }
164
165 void EM_backbuf_checkAndSelectTFaces(Mesh *me, int select)
166 {
167         MTFace *tface = me->mtface;
168         int a;
169
170         if (tface) {
171                 for(a=1; a<=me->totface; a++, tface++) {
172                         if(EM_check_backbuf(a)) {
173                                 tface->flag = select?(tface->flag|TF_SELECT):(tface->flag&~TF_SELECT);
174                         }
175                 }
176         }
177 }
178
179 void arrows_move_cursor(unsigned short event)
180 {
181         short mval[2];
182
183         getmouseco_sc(mval);
184
185         if(event==UPARROWKEY) {
186                 warp_pointer(mval[0], mval[1]+1);
187         } else if(event==DOWNARROWKEY) {
188                 warp_pointer(mval[0], mval[1]-1);
189         } else if(event==LEFTARROWKEY) {
190                 warp_pointer(mval[0]-1, mval[1]);
191         } else if(event==RIGHTARROWKEY) {
192                 warp_pointer(mval[0]+1, mval[1]);
193         }
194 }
195
196 /* simple API for object selection, rather than just using the flag
197  * this takes into account the 'restrict selection in 3d view' flag.
198  * deselect works always, the restriction just prevents selection */
199 void select_base_v3d(Base *base, short mode)
200 {
201         if (base) {
202                 if (mode==BA_SELECT) {
203                         if (!(base->object->restrictflag & OB_RESTRICT_SELECT))
204                                 if (mode==BA_SELECT) base->flag |= SELECT;
205                 }
206                 else if (mode==BA_DESELECT) {
207                         base->flag &= ~SELECT;
208                 }
209         }
210 }
211
212 /* *********************** GESTURE AND LASSO ******************* */
213
214 /* helper also for borderselect */
215 static int edge_fully_inside_rect(rcti *rect, short x1, short y1, short x2, short y2)
216 {
217         return BLI_in_rcti(rect, x1, y1) && BLI_in_rcti(rect, x2, y2);
218 }
219
220 static int edge_inside_rect(rcti *rect, short x1, short y1, short x2, short y2)
221 {
222         int d1, d2, d3, d4;
223         
224         /* check points in rect */
225         if(edge_fully_inside_rect(rect, x1, y1, x2, y2)) return 1;
226         
227         /* check points completely out rect */
228         if(x1<rect->xmin && x2<rect->xmin) return 0;
229         if(x1>rect->xmax && x2>rect->xmax) return 0;
230         if(y1<rect->ymin && y2<rect->ymin) return 0;
231         if(y1>rect->ymax && y2>rect->ymax) return 0;
232         
233         /* simple check lines intersecting. */
234         d1= (y1-y2)*(x1- rect->xmin ) + (x2-x1)*(y1- rect->ymin );
235         d2= (y1-y2)*(x1- rect->xmin ) + (x2-x1)*(y1- rect->ymax );
236         d3= (y1-y2)*(x1- rect->xmax ) + (x2-x1)*(y1- rect->ymax );
237         d4= (y1-y2)*(x1- rect->xmax ) + (x2-x1)*(y1- rect->ymin );
238         
239         if(d1<0 && d2<0 && d3<0 && d4<0) return 0;
240         if(d1>0 && d2>0 && d3>0 && d4>0) return 0;
241         
242         return 1;
243 }
244
245
246 #define MOVES_GESTURE 50
247 #define MOVES_LASSO 500
248
249 static int lasso_inside(short mcords[][2], short moves, short sx, short sy)
250 {
251         /* we do the angle rule, define that all added angles should be about zero or 2*PI */
252         float angletot=0.0, len, dot, ang, cross, fp1[2], fp2[2];
253         int a;
254         short *p1, *p2;
255         
256         if(sx==IS_CLIPPED)
257                 return 0;
258         
259         p1= mcords[moves-1];
260         p2= mcords[0];
261         
262         /* first vector */
263         fp1[0]= (float)(p1[0]-sx);
264         fp1[1]= (float)(p1[1]-sy);
265         len= sqrt(fp1[0]*fp1[0] + fp1[1]*fp1[1]);
266         fp1[0]/= len;
267         fp1[1]/= len;
268         
269         for(a=0; a<moves; a++) {
270                 /* second vector */
271                 fp2[0]= (float)(p2[0]-sx);
272                 fp2[1]= (float)(p2[1]-sy);
273                 len= sqrt(fp2[0]*fp2[0] + fp2[1]*fp2[1]);
274                 fp2[0]/= len;
275                 fp2[1]/= len;
276                 
277                 /* dot and angle and cross */
278                 dot= fp1[0]*fp2[0] + fp1[1]*fp2[1];
279                 ang= fabs(saacos(dot));
280
281                 cross= (float)((p1[1]-p2[1])*(p1[0]-sx) + (p2[0]-p1[0])*(p1[1]-sy));
282                 
283                 if(cross<0.0) angletot-= ang;
284                 else angletot+= ang;
285                 
286                 /* circulate */
287                 fp1[0]= fp2[0]; fp1[1]= fp2[1];
288                 p1= p2;
289                 p2= mcords[a+1];
290         }
291         
292         if( fabs(angletot) > 4.0 ) return 1;
293         return 0;
294 }
295
296 /* edge version for lasso select. we assume boundbox check was done */
297 static int lasso_inside_edge(short mcords[][2], short moves, int x0, int y0, int x1, int y1)
298 {
299         short v1[2], v2[2];
300         int a;
301
302         if(x0==IS_CLIPPED || x1==IS_CLIPPED)
303                 return 0;
304         
305         v1[0] = x0, v1[1] = y0;
306         v2[0] = x1, v2[1] = y1;
307
308         /* check points in lasso */
309         if(lasso_inside(mcords, moves, v1[0], v1[1])) return 1;
310         if(lasso_inside(mcords, moves, v2[0], v2[1])) return 1;
311         
312         /* no points in lasso, so we have to intersect with lasso edge */
313         
314         if( IsectLL2Ds(mcords[0], mcords[moves-1], v1, v2) > 0) return 1;
315         for(a=0; a<moves-1; a++) {
316                 if( IsectLL2Ds(mcords[a], mcords[a+1], v1, v2) > 0) return 1;
317         }
318         
319         return 0;
320 }
321
322
323 /* warning; lasso select with backbuffer-check draws in backbuf with persp(PERSP_WIN) 
324    and returns with persp(PERSP_VIEW). After lasso select backbuf is not OK
325 */
326 static void do_lasso_select_pose(Object *ob, short mcords[][2], short moves, short select)
327 {
328         bPoseChannel *pchan;
329         float vec[3];
330         short sco1[2], sco2[2];
331         
332         if(ob->type!=OB_ARMATURE || ob->pose==NULL) return;
333         
334         for(pchan= ob->pose->chanbase.first; pchan; pchan= pchan->next) {
335                 VECCOPY(vec, pchan->pose_head);
336                 Mat4MulVecfl(ob->obmat, vec);
337                 project_short(vec, sco1);
338                 VECCOPY(vec, pchan->pose_tail);
339                 Mat4MulVecfl(ob->obmat, vec);
340                 project_short(vec, sco2);
341                 
342                 if(lasso_inside_edge(mcords, moves, sco1[0], sco1[1], sco2[0], sco2[1])) {
343                         if(select) pchan->bone->flag |= BONE_SELECTED;
344                         else pchan->bone->flag &= ~(BONE_ACTIVE|BONE_SELECTED);
345                 }
346         }
347 }
348
349
350 static void do_lasso_select_objects(short mcords[][2], short moves, short select)
351 {
352         Base *base;
353         
354         for(base= G.scene->base.first; base; base= base->next) {
355                 if(base->lay & G.vd->lay) {
356                         project_short(base->object->obmat[3], &base->sx);
357                         if(lasso_inside(mcords, moves, base->sx, base->sy)) {
358                                 
359                                 if(select) select_base_v3d(base, BA_SELECT);
360                                 else select_base_v3d(base, BA_DESELECT);
361                                 base->object->flag= base->flag;
362                         }
363                         if(base->object->flag & OB_POSEMODE) {
364                                 do_lasso_select_pose(base->object, mcords, moves, select);
365                         }
366                 }
367         }
368 }
369
370 static void lasso_select_boundbox(rcti *rect, short mcords[][2], short moves)
371 {
372         short a;
373         
374         rect->xmin= rect->xmax= mcords[0][0];
375         rect->ymin= rect->ymax= mcords[0][1];
376         
377         for(a=1; a<moves; a++) {
378                 if(mcords[a][0]<rect->xmin) rect->xmin= mcords[a][0];
379                 else if(mcords[a][0]>rect->xmax) rect->xmax= mcords[a][0];
380                 if(mcords[a][1]<rect->ymin) rect->ymin= mcords[a][1];
381                 else if(mcords[a][1]>rect->ymax) rect->ymax= mcords[a][1];
382         }
383 }
384
385 static void do_lasso_select_mesh__doSelectVert(void *userData, EditVert *eve, int x, int y, int index)
386 {
387         struct { rcti *rect; short (*mcords)[2], moves, select, pass, done; } *data = userData;
388
389         if (BLI_in_rcti(data->rect, x, y) && lasso_inside(data->mcords, data->moves, x, y)) {
390                 eve->f = data->select?(eve->f|1):(eve->f&~1);
391         }
392 }
393 static void do_lasso_select_mesh__doSelectEdge(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index)
394 {
395         struct { rcti *rect; short (*mcords)[2], moves, select, pass, done; } *data = userData;
396
397         if (EM_check_backbuf(em_solidoffs+index)) {
398                 if (data->pass==0) {
399                         if (    edge_fully_inside_rect(data->rect, x0, y0, x1, y1)  &&
400                                         lasso_inside(data->mcords, data->moves, x0, y0) &&
401                                         lasso_inside(data->mcords, data->moves, x1, y1)) {
402                                 EM_select_edge(eed, data->select);
403                                 data->done = 1;
404                         }
405                 } else {
406                         if (lasso_inside_edge(data->mcords, data->moves, x0, y0, x1, y1)) {
407                                 EM_select_edge(eed, data->select);
408                         }
409                 }
410         }
411 }
412 static void do_lasso_select_mesh__doSelectFace(void *userData, EditFace *efa, int x, int y, int index)
413 {
414         struct { rcti *rect; short (*mcords)[2], moves, select, pass, done; } *data = userData;
415
416         if (BLI_in_rcti(data->rect, x, y) && lasso_inside(data->mcords, data->moves, x, y)) {
417                 EM_select_face_fgon(efa, data->select);
418         }
419 }
420
421 static void do_lasso_select_mesh(short mcords[][2], short moves, short select)
422 {
423         struct { rcti *rect; short (*mcords)[2], moves, select, pass, done; } data;
424         EditMesh *em = G.editMesh;
425         rcti rect;
426         int bbsel;
427         
428         lasso_select_boundbox(&rect, mcords, moves);
429         
430         data.rect = &rect;
431         data.mcords = mcords;
432         data.moves = moves;
433         data.select = select;
434         data.done = 0;
435         data.pass = 0;
436
437         bbsel= EM_mask_init_backbuf_border(mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
438         
439         if(G.scene->selectmode & SCE_SELECT_VERTEX) {
440                 if (bbsel) {
441                         EM_backbuf_checkAndSelectVerts(em, select);
442                 } else {
443                         mesh_foreachScreenVert(do_lasso_select_mesh__doSelectVert, &data, 1);
444                 }
445         }
446         if(G.scene->selectmode & SCE_SELECT_EDGE) {
447                         /* Does both bbsel and non-bbsel versions (need screen cos for both) */
448
449                 data.pass = 0;
450                 mesh_foreachScreenEdge(do_lasso_select_mesh__doSelectEdge, &data, 0);
451
452                 if (data.done==0) {
453                         data.pass = 1;
454                         mesh_foreachScreenEdge(do_lasso_select_mesh__doSelectEdge, &data, 0);
455                 }
456         }
457         
458         if(G.scene->selectmode & SCE_SELECT_FACE) {
459                 if (bbsel) {
460                         EM_backbuf_checkAndSelectFaces(em, select);
461                 } else {
462                         mesh_foreachScreenFace(do_lasso_select_mesh__doSelectFace, &data);
463                 }
464         }
465         
466         EM_free_backbuf();
467         EM_selectmode_flush();  
468 }
469
470 static void do_lasso_select_curve__doSelect(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y)
471 {
472         struct { short (*mcords)[2]; short moves; short select; } *data = userData;
473
474         if (lasso_inside(data->mcords, data->moves, x, y)) {
475                 if (bp) {
476                         bp->f1 = data->select?(bp->f1|1):(bp->f1&~1);
477                 } else {
478                         if (beztindex==0) {
479                                 bezt->f1 = data->select?(bezt->f1|1):(bezt->f1&~1);
480                         } else if (beztindex==1) {
481                                 bezt->f2 = data->select?(bezt->f2|1):(bezt->f2&~1);
482                         } else {
483                                 bezt->f3 = data->select?(bezt->f3|1):(bezt->f3&~1);
484                         }
485                 }
486         }
487 }
488 static void do_lasso_select_curve(short mcords[][2], short moves, short select)
489 {
490         struct { short (*mcords)[2]; short moves; short select; } data;
491
492         data.mcords = mcords;
493         data.moves = moves;
494         data.select = select;
495
496         nurbs_foreachScreenVert(do_lasso_select_curve__doSelect, &data);
497 }
498
499 static void do_lasso_select_lattice__doSelect(void *userData, BPoint *bp, int x, int y)
500 {
501         struct { short (*mcords)[2]; short moves; short select; } *data = userData;
502
503         if (lasso_inside(data->mcords, data->moves, x, y)) {
504                 bp->f1 = data->select?(bp->f1|1):(bp->f1&~1);
505         }
506 }
507 static void do_lasso_select_lattice(short mcords[][2], short moves, short select)
508 {
509         struct { short (*mcords)[2]; short moves; short select; } data;
510
511         data.mcords = mcords;
512         data.moves = moves;
513         data.select = select;
514
515         lattice_foreachScreenVert(do_lasso_select_lattice__doSelect, &data);
516 }
517
518 static void do_lasso_select_armature(short mcords[][2], short moves, short select)
519 {
520         EditBone *ebone;
521         float vec[3];
522         short sco1[2], sco2[2], didpoint;
523         
524         for (ebone=G.edbo.first; ebone; ebone=ebone->next) {
525
526                 VECCOPY(vec, ebone->head);
527                 Mat4MulVecfl(G.obedit->obmat, vec);
528                 project_short(vec, sco1);
529                 VECCOPY(vec, ebone->tail);
530                 Mat4MulVecfl(G.obedit->obmat, vec);
531                 project_short(vec, sco2);
532                 
533                 didpoint= 0;
534                 if(lasso_inside(mcords, moves, sco1[0], sco1[1])) {
535                         if(select) ebone->flag |= BONE_ROOTSEL;
536                         else ebone->flag &= ~BONE_ROOTSEL;
537                         didpoint= 1;
538                 }
539                 if(lasso_inside(mcords, moves, sco2[0], sco2[1])) {
540                    if(select) ebone->flag |= BONE_TIPSEL;
541                    else ebone->flag &= ~BONE_TIPSEL;
542                    didpoint= 1;
543                 }
544                 /* if one of points selected, we skip the bone itself */
545                 if(didpoint==0 && lasso_inside_edge(mcords, moves, sco1[0], sco1[1], sco2[0], sco2[1])) {
546                         if(select) ebone->flag |= BONE_TIPSEL|BONE_ROOTSEL|BONE_SELECTED;
547                         else ebone->flag &= ~(BONE_ACTIVE|BONE_SELECTED|BONE_TIPSEL|BONE_ROOTSEL);
548                 }
549         }
550         countall();     /* abused for flushing selection */
551 }
552
553 static void do_lasso_select_facemode(short mcords[][2], short moves, short select)
554 {
555         Mesh *me;
556         rcti rect;
557         
558         me= get_mesh(OBACT);
559         if(me==NULL || me->mtface==NULL) return;
560         if(me->totface==0) return;
561         
562         em_vertoffs= me->totface+1;     /* max index array */
563         
564         lasso_select_boundbox(&rect, mcords, moves);
565         EM_mask_init_backbuf_border(mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
566         
567         EM_backbuf_checkAndSelectTFaces(me, select);
568         
569         EM_free_backbuf();
570         
571         object_tface_flags_changed(OBACT, 0);
572 }
573
574 static void do_lasso_select(short mcords[][2], short moves, short select)
575 {
576         if(G.obedit==NULL) {
577                 if(G.f & G_FACESELECT)
578                         do_lasso_select_facemode(mcords, moves, select);
579                 else if(G.f & (G_VERTEXPAINT|G_TEXTUREPAINT|G_WEIGHTPAINT))
580                         ;
581                 else  
582                         do_lasso_select_objects(mcords, moves, select);
583         }
584         else if(G.obedit->type==OB_MESH) 
585                 do_lasso_select_mesh(mcords, moves, select);
586         else if(G.obedit->type==OB_CURVE || G.obedit->type==OB_SURF) 
587                 do_lasso_select_curve(mcords, moves, select);
588         else if(G.obedit->type==OB_LATTICE) 
589                 do_lasso_select_lattice(mcords, moves, select);
590         else if(G.obedit->type==OB_ARMATURE)
591                 do_lasso_select_armature(mcords, moves, select);
592         
593         BIF_undo_push("Lasso select");
594
595         allqueue(REDRAWVIEW3D, 0);
596         countall();
597 }
598
599 /* un-draws and draws again */
600 static void draw_lasso_select(short mcords[][2], short moves, short end)
601 {
602         int a;
603         
604         setlinestyle(2);
605         /* clear draw */
606         if(moves>1) {
607                 for(a=1; a<=moves-1; a++) {
608                         sdrawXORline(mcords[a-1][0], mcords[a-1][1], mcords[a][0], mcords[a][1]);
609                 }
610                 sdrawXORline(mcords[moves-1][0], mcords[moves-1][1], mcords[0][0], mcords[0][1]);
611         }
612         if(!end) {
613                 /* new draw */
614                 for(a=1; a<=moves; a++) {
615                         sdrawXORline(mcords[a-1][0], mcords[a-1][1], mcords[a][0], mcords[a][1]);
616                 }
617                 sdrawXORline(mcords[moves][0], mcords[moves][1], mcords[0][0], mcords[0][1]);
618         }
619         setlinestyle(0);
620 }
621
622
623 static char interpret_move(short mcord[][2], int count)
624 {
625         float x1, x2, y1, y2, d1, d2, inp, sq, mouse[MOVES_GESTURE][2];
626         int i, j, dir = 0;
627         
628         if (count <= 10) return ('g');
629
630         /* from short to float (drawing is with shorts) */
631         for(j=0; j<count; j++) {
632                 mouse[j][0]= mcord[j][0];
633                 mouse[j][1]= mcord[j][1];
634         }
635         
636         /* new method:
637          * 
638          * starting from end points, calculate centre with maximum distance
639          * dependant at the angle s / g / r is defined
640          */
641         
642
643         /* filter */
644         
645         for( j = 3 ; j > 0; j--){
646                 x1 = mouse[1][0];
647                 y1 = mouse[1][1];
648                 for (i = 2; i < count; i++){
649                         x2 = mouse[i-1][0];
650                         y2 = mouse[i-1][1];
651                         mouse[i-1][0] = ((x1 + mouse[i][0]) /4.0) + (x2 / 2.0);
652                         mouse[i-1][1] = ((y1 + mouse[i][1]) /4.0) + (y2 / 2.0);
653                         x1 = x2;
654                         y1 = y2;
655                 }
656         }
657
658         /* make overview of directions */
659         for (i = 0; i <= count - 2; i++){
660                 x1 = mouse[i][0] - mouse[i + 1][0];
661                 y1 = mouse[i][1] - mouse[i + 1][1];
662
663                 if (x1 < -0.5){
664                         if (y1 < -0.5) dir |= 32;
665                         else if (y1 > 0.5) dir |= 128;
666                         else dir |= 64;
667                 } else if (x1 > 0.5){
668                         if (y1 < -0.5) dir |= 8;
669                         else if (y1 > 0.5) dir |= 2;
670                         else dir |= 4;
671                 } else{
672                         if (y1 < -0.5) dir |= 16;
673                         else if (y1 > 0.5) dir |= 1;
674                         else dir |= 0;
675                 }
676         }
677         
678         /* move all crosses to the right */
679         for (i = 7; i>=0 ; i--){
680                 if (dir & 128) dir = (dir << 1) + 1;
681                 else break;
682         }
683         dir &= 255;
684         for (i = 7; i>=0 ; i--){
685                 if ((dir & 1) == 0) dir >>= 1;
686                 else break;
687         }
688         
689         /* in theory: 1 direction: straight line
690      * multiple sequential directions: circle
691      * non-sequential, and 1 bit set in upper 4 bits: size
692      */
693         switch(dir){
694         case 1:
695                 return ('g');
696                 break;
697         case 3:
698         case 7:
699                 x1 = mouse[0][0] - mouse[count >> 1][0];
700                 y1 = mouse[0][1] - mouse[count >> 1][1];
701                 x2 = mouse[count >> 1][0] - mouse[count - 1][0];
702                 y2 = mouse[count >> 1][1] - mouse[count - 1][1];
703                 d1 = (x1 * x1) + (y1 * y1);
704                 d2 = (x2 * x2) + (y2 * y2);
705                 sq = sqrt(d1);
706                 x1 /= sq; 
707                 y1 /= sq;
708                 sq = sqrt(d2);
709                 x2 /= sq; 
710                 y2 /= sq;
711                 inp = (x1 * x2) + (y1 * y2);
712                 /*printf("%f\n", inp);*/
713                 if (inp > 0.9) return ('g');
714                 else return ('r');
715                 break;
716         case 15:
717         case 31:
718         case 63:
719         case 127:
720         case 255:
721                 return ('r');
722                 break;
723         default:
724                 /* for size at least one of the higher bits has to be set */
725                 if (dir < 16) return ('r');
726                 else return ('s');
727         }
728
729         return (0);
730 }
731
732
733 /* return 1 to denote gesture did something, also does lasso */
734 int gesture(void)
735 {
736         unsigned short event=0;
737         int i= 1, end= 0, a;
738         short mcords[MOVES_LASSO][2]; /* the larger size */
739         short mval[2], val, timer=0, mousebut, lasso=0, maxmoves;
740         
741         if (U.flag & USER_LMOUSESELECT) mousebut = R_MOUSE;
742         else mousebut = L_MOUSE;
743         
744         /* check for lasso */
745         if(G.qual & LR_CTRLKEY) {
746                 if(curarea->spacetype==SPACE_VIEW3D) {
747                         if(G.obedit==NULL) {
748                                 if(G.f & (G_VERTEXPAINT|G_TEXTUREPAINT|G_WEIGHTPAINT)) return 0;
749                         }
750                         lasso= 1;
751                 }
752         }
753         
754         glDrawBuffer(GL_FRONT);
755         persp(PERSP_WIN);       /*  ortho at pixel level */
756         
757         getmouseco_areawin(mval);
758         
759         mcords[0][0] = mval[0];
760         mcords[0][1] = mval[1];
761         
762         if(lasso) maxmoves= MOVES_LASSO;
763         else maxmoves= MOVES_GESTURE;
764         
765         while(get_mbut() & mousebut) {
766                 
767                 if(qtest()) event= extern_qread(&val);
768                 else if(i==1) {
769                         /* not drawing yet... check for toolbox */
770                         PIL_sleep_ms(10);
771                         timer++;
772                         if(timer>=10*U.tb_leftmouse) {
773                                 glDrawBuffer(GL_BACK); /* !! */
774                                 toolbox_n();
775                                 return 1;
776                         }
777                 }
778                 
779                 switch (event) {
780                 case MOUSEY:
781                         getmouseco_areawin(mval);
782                         if( abs(mval[0]-mcords[i-1][0])>3 || abs(mval[1]-mcords[i-1][1])>3 ) {
783                                 mcords[i][0] = mval[0];
784                                 mcords[i][1] = mval[1];
785                                 
786                                 if(i) {
787                                         if(lasso) draw_lasso_select(mcords, i, 0);
788                                         else sdrawXORline(mcords[i-1][0], mcords[i-1][1], mcords[i][0], mcords[i][1]);
789                                         bglFlush();
790                                 }
791                                 i++;
792                         }
793                         break;
794                 case MOUSEX:
795                         break;
796                 case LEFTMOUSE:
797                         break;
798                 default:
799                         if(event) end= 1;       /* blender returns 0 */
800                         break;
801                 }
802                 if (i == maxmoves || end == 1) break;
803         }
804         
805         /* clear */
806         if(lasso) draw_lasso_select(mcords, i, 1);
807         else for(a=1; a<i; a++) {
808                 sdrawXORline(mcords[a-1][0], mcords[a-1][1], mcords[a][0], mcords[a][1]);
809         }
810         
811         persp(PERSP_VIEW);
812         glDrawBuffer(GL_BACK);
813         
814         if (i > 2) {
815                 if(lasso) do_lasso_select(mcords, i, (G.qual & LR_SHIFTKEY)==0);
816                 else {
817                         i = interpret_move(mcords, i);
818                         
819                         if(i) {
820                                 if(curarea->spacetype==SPACE_IPO) transform_ipo(i);
821                                 else if(curarea->spacetype==SPACE_OOPS) transform_oops('g', 0);
822                                 else {
823                                         int context;
824
825                                         if(curarea->spacetype==SPACE_IMAGE) context= CTX_NONE;
826                                         else context= CTX_NONE;
827
828                                         if(i=='g') {
829                                                 initTransform(TFM_TRANSLATION, context);
830                                                 Transform();
831                                         }
832                                         else if(i=='r') {
833                                                 initTransform(TFM_ROTATION, context);
834                                                 Transform();
835                                         }
836                                         else {
837                                                 initTransform(TFM_RESIZE, context);
838                                                 Transform();
839                                         }
840                                 }
841                         }
842                 }
843                 return 1;
844         }
845         return 0;
846 }
847
848 void mouse_cursor(void)
849 {
850         float dx, dy, fz, *fp = NULL, dvec[3], oldcurs[3];
851         short mval[2], mx, my, lr_click=0;
852         
853         if(gesture()) return;
854         
855         getmouseco_areawin(mval);
856
857         mx= mval[0];
858         my= mval[1];
859         
860         fp= give_cursor();
861         
862         if(G.obedit && ((G.qual & LR_CTRLKEY) || get_mbut()&R_MOUSE )) lr_click= 1;
863         VECCOPY(oldcurs, fp);
864         
865         project_short_noclip(fp, mval);
866
867         initgrabz(fp[0], fp[1], fp[2]);
868         
869         if(mval[0]!=IS_CLIPPED) {
870                 
871                 window_to_3d(dvec, mval[0]-mx, mval[1]-my);
872                 VecSubf(fp, fp, dvec);
873                 
874         }
875         else {
876
877                 dx= ((float)(mx-(curarea->winx/2)))*G.vd->zfac/(curarea->winx/2);
878                 dy= ((float)(my-(curarea->winy/2)))*G.vd->zfac/(curarea->winy/2);
879                 
880                 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];
881                 fz= fz/G.vd->zfac;
882                 
883                 fp[0]= (G.vd->persinv[0][0]*dx + G.vd->persinv[1][0]*dy+ G.vd->persinv[2][0]*fz)-G.vd->ofs[0];
884                 fp[1]= (G.vd->persinv[0][1]*dx + G.vd->persinv[1][1]*dy+ G.vd->persinv[2][1]*fz)-G.vd->ofs[1];
885                 fp[2]= (G.vd->persinv[0][2]*dx + G.vd->persinv[1][2]*dy+ G.vd->persinv[2][2]*fz)-G.vd->ofs[2];
886         }
887         
888         allqueue(REDRAWVIEW3D, 1);
889         
890         if(lr_click) {
891                 if(G.obedit->type==OB_MESH) add_click_mesh();
892                 else if ELEM(G.obedit->type, OB_CURVE, OB_SURF) addvert_Nurb(0);
893                 else if (G.obedit->type==OB_ARMATURE) addvert_armature();
894                 VECCOPY(fp, oldcurs);
895         }
896         
897 }
898
899 void deselectall(void)  /* is toggle */
900 {
901         Base *base;
902         int a=0, ok=0; 
903
904         base= FIRSTBASE;
905         while(base) {
906                 /* is there a visible selected object */
907                 if TESTBASE(base) {
908                         ok= a= 1;
909                         break;
910                 }
911                 /* are there any objects in the view*/
912                 if(base->lay & G.vd->lay)
913                         ok=1;
914                 
915                 base= base->next;
916         }
917         
918         if (!ok) return;
919         
920         base= FIRSTBASE;
921         while(base) {
922                 if(base->lay & G.vd->lay) {
923                         if(a) 
924                                 select_base_v3d(base, BA_DESELECT);
925                         else 
926                                 select_base_v3d(base, BA_SELECT);
927                         base->object->flag= base->flag;
928                 }
929                 base= base->next;
930         }
931
932         allqueue(REDRAWVIEW3D, 0);
933         allqueue(REDRAWDATASELECT, 0);
934         allqueue(REDRAWNLA, 0);
935         
936         countall();
937         BIF_undo_push("(De)select all");
938 }
939
940 /* inverts object selection */
941 void selectswap(void)
942 {
943         Base *base;
944
945         for(base= FIRSTBASE; base; base= base->next) {
946                 if(base->lay & G.vd->lay) {
947                         if TESTBASE(base)
948                                 select_base_v3d(base, BA_DESELECT);
949                         else
950                                 select_base_v3d(base, BA_SELECT);
951                         base->object->flag= base->flag;
952                 }
953         }
954
955         allqueue(REDRAWVIEW3D, 0);
956         allqueue(REDRAWDATASELECT, 0);
957         allqueue(REDRAWNLA, 0);
958         
959         countall();
960         BIF_undo_push("Select Inverse");
961 }
962
963
964 /* selects all objects of a particular type, on currently visible layers */
965 void selectall_type(short obtype) 
966 {
967         Base *base;
968         
969         base= FIRSTBASE;
970         while(base) {
971                 if((base->lay & G.vd->lay) && (base->object->type == obtype)) {
972                         select_base_v3d(base, BA_SELECT);
973                         base->object->flag= base->flag;
974                 }
975                 base= base->next;
976         }
977
978         allqueue(REDRAWVIEW3D, 0);
979         allqueue(REDRAWDATASELECT, 0);
980         allqueue(REDRAWNLA, 0);
981         
982         countall();
983         BIF_undo_push("Select all per type");
984 }
985 /* selects all objects on a particular layer */
986 void selectall_layer(unsigned int layernum) 
987 {
988         Base *base;
989         
990         base= FIRSTBASE;
991         while(base) {
992                 if (base->lay == (1<< (layernum -1))) {
993                         select_base_v3d(base, BA_SELECT);
994                         base->object->flag= base->flag;
995                 }
996                 base= base->next;
997         }
998
999         allqueue(REDRAWVIEW3D, 0);
1000         allqueue(REDRAWDATASELECT, 0);
1001         allqueue(REDRAWNLA, 0);
1002         
1003         countall();
1004         BIF_undo_push("Select all per layer");
1005 }
1006
1007 static void deselectall_except(Base *b)   /* deselect all except b */
1008 {
1009         Base *base;
1010
1011         base= FIRSTBASE;
1012         while(base) {
1013                 if (base->flag & SELECT) {
1014                         if(b!=base) {
1015                                 select_base_v3d(base, BA_DESELECT);
1016                                 base->object->flag= base->flag;
1017                         }
1018                 }
1019                 base= base->next;
1020         }
1021 }
1022
1023 #if 0
1024 /* smart function to sample a rect spiralling outside, nice for backbuf selection */
1025 static unsigned int samplerect(unsigned int *buf, int size, unsigned int dontdo)
1026 {
1027         Base *base;
1028         unsigned int *bufmin,*bufmax;
1029         int a,b,rc,tel,aantal,dirvec[4][2],maxob;
1030         unsigned int retval=0;
1031         
1032         base= LASTBASE;
1033         if(base==0) return 0;
1034         maxob= base->selcol;
1035
1036         aantal= (size-1)/2;
1037         rc= 0;
1038
1039         dirvec[0][0]= 1;
1040         dirvec[0][1]= 0;
1041         dirvec[1][0]= 0;
1042         dirvec[1][1]= -size;
1043         dirvec[2][0]= -1;
1044         dirvec[2][1]= 0;
1045         dirvec[3][0]= 0;
1046         dirvec[3][1]= size;
1047
1048         bufmin= buf;
1049         bufmax= buf+ size*size;
1050         buf+= aantal*size+ aantal;
1051
1052         for(tel=1;tel<=size;tel++) {
1053
1054                 for(a=0;a<2;a++) {
1055                         for(b=0;b<tel;b++) {
1056
1057                                 if(*buf && *buf<=maxob && *buf!=dontdo) return *buf;
1058                                 if( *buf==dontdo ) retval= dontdo;      /* if only color dontdo is available, still return dontdo */
1059                                 
1060                                 buf+= (dirvec[rc][0]+dirvec[rc][1]);
1061
1062                                 if(buf<bufmin || buf>=bufmax) return retval;
1063                         }
1064                         rc++;
1065                         rc &= 3;
1066                 }
1067         }
1068         return retval;
1069 }
1070 #endif
1071
1072 void set_active_base(Base *base)
1073 {
1074         Base *tbase;
1075         
1076         BASACT= base;
1077         
1078         if(base) {
1079                 
1080                 /* signals to buttons */
1081                 redraw_test_buttons(base->object);
1082                 
1083                 /* signal to ipo */
1084                 allqueue(REDRAWIPO, base->object->ipowin);
1085                 
1086                 allqueue(REDRAWACTION, 0);
1087                 allqueue(REDRAWNLA, 0);
1088                 allqueue(REDRAWNODE, 0);
1089                 
1090                 /* signal to action */
1091                 select_actionchannel_by_name(base->object->action, "Object", 1);
1092                 
1093                 /* disable temporal locks */
1094                 for(tbase=FIRSTBASE; tbase; tbase= tbase->next) {
1095                         if(base!=tbase && (tbase->object->shapeflag & OB_SHAPE_TEMPLOCK)) {
1096                                 tbase->object->shapeflag &= ~OB_SHAPE_TEMPLOCK;
1097                                 DAG_object_flush_update(G.scene, tbase->object, OB_RECALC_DATA);
1098                         }
1099                 }
1100         }
1101 }
1102
1103 void set_active_object(Object *ob)
1104 {
1105         Base *base;
1106         
1107         for(base= FIRSTBASE; base; base= base->next) {
1108                 if(base->object==ob) {
1109                         set_active_base(base);
1110                         return;
1111                 }
1112         }
1113 }
1114
1115 static void select_all_from_groups(Base *basact)
1116 {
1117         Group *group;
1118         GroupObject *go;
1119         int deselect= basact->flag & SELECT;
1120         
1121         for(group= G.main->group.first; group; group= group->id.next) {
1122                 if(object_in_group(basact->object, group)) {
1123                         for(go= group->gobject.first; go; go= go->next) {
1124                                 if(deselect) go->ob->flag &= ~SELECT;
1125                                 else {
1126                                         if (!(go->ob->restrictflag & OB_RESTRICT_SELECT))
1127                                                 go->ob->flag |= SELECT;
1128                                 }
1129                         }
1130                 }
1131         }
1132         /* sync bases */
1133         for(basact= G.scene->base.first; basact; basact= basact->next) {
1134                 if(basact->object->flag & SELECT)
1135                         select_base_v3d(basact, BA_SELECT);
1136                 else
1137                         select_base_v3d(basact, BA_DESELECT);
1138         }
1139 }
1140
1141 /* The max number of menu items in an object select menu */
1142 #define SEL_MENU_SIZE 22
1143
1144 static Base *mouse_select_menu(unsigned int *buffer, int hits, short *mval)
1145 {
1146         Base *baseList[SEL_MENU_SIZE]={NULL}; /*baseList is used to store all possible bases to bring up a menu */
1147         Base *base;
1148         short baseCount = 0;
1149         char menuText[20 + SEL_MENU_SIZE*32] = "Select Object%t";       /* max ob name = 22 */
1150         char str[32];
1151         
1152         for(base=FIRSTBASE; base; base= base->next) {
1153                 if(base->lay & G.vd->lay) {
1154                         baseList[baseCount] = NULL;
1155                         
1156                         /* two selection methods, the CTRL select uses max dist of 15 */
1157                         if(buffer) {
1158                                 int a;
1159                                 for(a=0; a<hits; a++) {
1160                                         /* index was converted */
1161                                         if(base->selcol==buffer[ (4 * a) + 3 ]) baseList[baseCount] = base;
1162                                 }
1163                         }
1164                         else {
1165                                 int temp, dist=15;
1166                                 
1167                                 project_short(base->object->obmat[3], &base->sx);
1168                                 
1169                                 temp= abs(base->sx -mval[0]) + abs(base->sy -mval[1]);
1170                                 if(temp<dist ) baseList[baseCount] = base;
1171                         }
1172                         
1173                         if(baseList[baseCount]) {
1174                                 if (baseCount < SEL_MENU_SIZE) {
1175                                         baseList[baseCount] = base;
1176                                         sprintf(str, "|%s %%x%d", base->object->id.name+2, baseCount+1);        /* max ob name == 22 */
1177                                         strcat(menuText, str);
1178                                         baseCount++;
1179                                 }
1180                         }
1181                 }
1182         }
1183         
1184         if(baseCount<=1) return baseList[0];
1185         else {
1186                 baseCount = pupmenu(menuText);
1187                 
1188                 if (baseCount != -1) { /* If nothing is selected then dont do anything */
1189                         return baseList[baseCount-1];
1190                 }
1191                 else return NULL;
1192         }
1193 }
1194
1195 /* we want a select buffer with bones, if there are... */
1196 /* so check three selection levels and compare */
1197 static short mixed_bones_object_selectbuffer(unsigned int *buffer, short *mval)
1198 {
1199         int offs;
1200         short a, hits15, hits9=0, hits5=0;
1201         short has_bones15=0, has_bones9=0, has_bones5=0;
1202         
1203         hits15= view3d_opengl_select(buffer, MAXPICKBUF, mval[0]-14, mval[1]-14, mval[0]+14, mval[1]+14);
1204         if(hits15) {
1205                 for(a=0; a<hits15; a++) if(buffer[4*a+3] & 0xFFFF0000) has_bones15= 1;
1206                 
1207                 offs= 4*hits15;
1208                 hits9= view3d_opengl_select(buffer+offs, MAXPICKBUF-offs, mval[0]-9, mval[1]-9, mval[0]+9, mval[1]+9);
1209                 if(hits9) {
1210                         for(a=0; a<hits9; a++) if(buffer[offs+4*a+3] & 0xFFFF0000) has_bones9= 1;
1211                         
1212                         offs+= 4*hits9;
1213                         hits5= view3d_opengl_select(buffer+offs, MAXPICKBUF-offs, mval[0]-5, mval[1]-5, mval[0]+5, mval[1]+5);
1214                         if(hits5) {
1215                                 for(a=0; a<hits5; a++) if(buffer[offs+4*a+3] & 0xFFFF0000) has_bones5= 1;
1216                         }
1217                 }
1218                 
1219                 if(has_bones5) {
1220                         offs= 4*hits15 + 4*hits9;
1221                         memcpy(buffer, buffer+offs, 4*offs);
1222                         return hits5;
1223                 }
1224                 if(has_bones9) {
1225                         offs= 4*hits15;
1226                         memcpy(buffer, buffer+offs, 4*offs);
1227                         return hits9;
1228                 }
1229                 if(has_bones15) {
1230                         return hits15;
1231                 }
1232                 
1233                 if(hits5) {
1234                         offs= 4*hits15 + 4*hits9;
1235                         memcpy(buffer, buffer+offs, 4*offs);
1236                         return hits5;
1237                 }
1238                 if(hits9) {
1239                         offs= 4*hits15;
1240                         memcpy(buffer, buffer+offs, 4*offs);
1241                         return hits9;
1242                 }
1243                 return hits15;
1244         }
1245         
1246         return 0;
1247 }
1248
1249 void mouse_select(void)
1250 {
1251         Base *base, *startbase=NULL, *basact=NULL, *oldbasact=NULL;
1252         unsigned int buffer[MAXPICKBUF];
1253         int temp, a, dist=100;
1254         short hits, mval[2];
1255
1256         /* always start list from basact in wire mode */
1257         startbase=  FIRSTBASE;
1258         if(BASACT && BASACT->next) startbase= BASACT->next;
1259
1260         getmouseco_areawin(mval);
1261         
1262         /* This block uses the control key to make the object selected by its centre point rather then its contents */
1263         if(G.obedit==0 && (G.qual & LR_CTRLKEY)) {
1264                 
1265                 /* note; shift+alt goes to group-flush-selecting */
1266                 if(G.qual == (LR_ALTKEY|LR_CTRLKEY)) 
1267                         basact= mouse_select_menu(NULL, 0, mval);
1268                 else {
1269                         base= startbase;
1270                         while(base) {
1271                                 
1272                                 if(base->lay & G.vd->lay) {
1273                                         
1274                                         project_short(base->object->obmat[3], &base->sx);
1275                                         
1276                                         temp= abs(base->sx -mval[0]) + abs(base->sy -mval[1]);
1277                                         if(base==BASACT) temp+=10;
1278                                         if(temp<dist ) {
1279                                                 
1280                                                 dist= temp;
1281                                                 basact= base;
1282                                         }
1283                                 }
1284                                 base= base->next;
1285                                 
1286                                 if(base==0) base= FIRSTBASE;
1287                                 if(base==startbase) break;
1288                         }
1289                 }
1290         }
1291         else {
1292                 /* if objects have posemode set, the bones are in the same selection buffer */
1293                 
1294                 hits= mixed_bones_object_selectbuffer(buffer, mval);
1295                 
1296                 if(hits>0) {
1297                         int has_bones= 0;
1298                         
1299                         for(a=0; a<hits; a++) if(buffer[4*a+3] & 0xFFFF0000) has_bones= 1;
1300
1301                         /* note; shift+alt goes to group-flush-selecting */
1302                         if(has_bones==0 && (G.qual == LR_ALTKEY)) 
1303                                 basact= mouse_select_menu(buffer, hits, mval);
1304                         else {
1305                                 static short lastmval[2]={-100, -100};
1306                                 int donearest= 0;
1307                                 
1308                                 /* define if we use solid nearest select or not */
1309                                 if(G.vd->drawtype>OB_WIRE) {
1310                                         donearest= 1;
1311                                         if( ABS(mval[0]-lastmval[0])<3 && ABS(mval[1]-lastmval[1])<3) {
1312                                                 if(!has_bones)  /* hrms, if theres bones we always do nearest */
1313                                                         donearest= 0;
1314                                         }
1315                                 }
1316                                 lastmval[0]= mval[0]; lastmval[1]= mval[1];
1317                                 
1318                                 if(donearest) {
1319                                         unsigned int min= 0xFFFFFFFF;
1320                                         int selcol= 0, notcol=0;
1321                                         
1322
1323                                         if(has_bones) {
1324                                                 /* we skip non-bone hits */
1325                                                 for(a=0; a<hits; a++) {
1326                                                         if( min > buffer[4*a+1] && (buffer[4*a+3] & 0xFFFF0000) ) {
1327                                                                 min= buffer[4*a+1];
1328                                                                 selcol= buffer[4*a+3] & 0xFFFF;
1329                                                         }
1330                                                 }
1331                                         }
1332                                         else {
1333                                                 /* only exclude active object when it is selected... */
1334                                                 if(BASACT && (BASACT->flag & SELECT) && hits>1) notcol= BASACT->selcol; 
1335                                         
1336                                                 for(a=0; a<hits; a++) {
1337                                                         if( min > buffer[4*a+1] && notcol!=(buffer[4*a+3] & 0xFFFF)) {
1338                                                                 min= buffer[4*a+1];
1339                                                                 selcol= buffer[4*a+3] & 0xFFFF;
1340                                                         }
1341                                                 }
1342                                         }
1343
1344                                         base= FIRSTBASE;
1345                                         while(base) {
1346                                                 if(base->lay & G.vd->lay) {
1347                                                         if(base->selcol==selcol) break;
1348                                                 }
1349                                                 base= base->next;
1350                                         }
1351                                         if(base) basact= base;
1352                                 }
1353                                 else {
1354                                         
1355                                         base= startbase;
1356                                         while(base) {
1357                                                 /* skip objects with select restriction, to prevent prematurely ending this loop
1358                                                  * with an un-selectable choice */
1359                                                 if (base->object->restrictflag & OB_RESTRICT_SELECT) {
1360                                                         base=base->next;
1361                                                         if(base==NULL) base= FIRSTBASE;
1362                                                         if(base==startbase) break;
1363                                                 }
1364                                         
1365                                                 if(base->lay & G.vd->lay) {
1366                                                         for(a=0; a<hits; a++) {
1367                                                                 if(has_bones) {
1368                                                                         /* skip non-bone objects */
1369                                                                         if((buffer[4*a+3] & 0xFFFF0000)) {
1370                                                                                 if(base->selcol== (buffer[(4*a)+3] & 0xFFFF))
1371                                                                                         basact= base;
1372                                                                         }
1373                                                                 }
1374                                                                 else {
1375                                                                         if(base->selcol== (buffer[(4*a)+3] & 0xFFFF))
1376                                                                                 basact= base;
1377                                                                 }
1378                                                         }
1379                                                 }
1380                                                 
1381                                                 if(basact) break;
1382                                                 
1383                                                 base= base->next;
1384                                                 if(base==NULL) base= FIRSTBASE;
1385                                                 if(base==startbase) break;
1386                                         }
1387                                 }
1388                         }
1389                         
1390                         if(has_bones && basact) {
1391                                 if( do_pose_selectbuffer(basact, buffer, hits) ) {      /* then bone is found */
1392                                 
1393                                         /* in weightpaint, we use selected bone to select vertexgroup, so no switch to new active object */
1394                                         if(G.f & G_WEIGHTPAINT) {
1395                                                 /* we make the armature selected */
1396                                                 basact->flag|= SELECT;
1397                                                 basact->object->flag= basact->flag;
1398                                                 /* prevent activating */
1399                                                 basact= NULL;
1400                                         }
1401                                 }
1402                                 /* prevent bone selecting to pass on to object selecting */
1403                                 if(basact==BASACT)
1404                                         basact= NULL;
1405                         }
1406                 }
1407         }
1408         
1409         /* so, do we have something selected? */
1410         if(basact) {
1411                 
1412                 if(G.obedit) {
1413                         /* only do select */
1414                         deselectall_except(basact);
1415                         select_base_v3d(basact, BA_SELECT);
1416                 }
1417                 /* also prevent making it active on mouse selection */
1418                 else if (!(basact->object->restrictflag & OB_RESTRICT_SELECT)) {
1419
1420                         oldbasact= BASACT;
1421                         BASACT= basact;
1422                         
1423                         if((G.qual & LR_SHIFTKEY)==0) {
1424                                 deselectall_except(basact);
1425                                 select_base_v3d(basact, BA_SELECT);
1426                         }
1427                         else if(G.qual==(LR_SHIFTKEY|LR_ALTKEY)) {
1428                                 select_all_from_groups(basact);
1429                         }
1430                         else {
1431                                 if(basact->flag & SELECT) {
1432                                         if(basact==oldbasact)
1433                                                 select_base_v3d(basact, BA_DESELECT);
1434                                 }
1435                                 else select_base_v3d(basact, BA_SELECT);
1436                         }
1437
1438                         /* copy */
1439                         basact->object->flag= basact->flag;
1440                         
1441                         if(oldbasact != basact) {
1442                                         set_active_base(basact);
1443                         }
1444
1445                         /* for visual speed, only in wire mode */
1446                         if(G.vd->drawtype==OB_WIRE) {
1447                                 /* however, not for posemodes */
1448                                 if(basact->object->flag & OB_POSEMODE);
1449                                 else if(oldbasact && (oldbasact->object->flag & OB_POSEMODE));
1450                                 else {
1451                                         if(oldbasact && oldbasact != basact && (oldbasact->lay & G.vd->lay)) 
1452                                                 draw_object_ext(oldbasact);
1453                                         draw_object_ext(basact);
1454                                 }
1455                         }
1456                         
1457                         /* selecting a non-mesh, should end a couple of modes... */
1458                         if(basact->object->type!=OB_MESH) {
1459                                 if(G.f & G_SCULPTMODE) {
1460                                         set_sculptmode();
1461                                 }
1462                                 if(G.f & G_WEIGHTPAINT) {
1463                                         set_wpaint();   /* toggle */
1464                                 }
1465                                 if(G.f & G_VERTEXPAINT) {
1466                                         set_vpaint();   /* toggle */
1467                                 }
1468                         }
1469                         /* always end this */
1470                         if(G.f & G_FACESELECT) {
1471                                 set_faceselect();       /* toggle */
1472                         }
1473                         
1474                         allqueue(REDRAWBUTSLOGIC, 0);
1475                         allqueue(REDRAWDATASELECT, 0);
1476                         allqueue(REDRAWBUTSOBJECT, 0);
1477                         allqueue(REDRAWACTION, 0);
1478                         allqueue(REDRAWNLA, 0);
1479                         allqueue(REDRAWTIME, 0);
1480                         allqueue(REDRAWHEADERS, 0);     /* To force display update for the posebutton */
1481                 }
1482                 /* also because multiple 3d windows can be open */
1483                 allqueue(REDRAWVIEW3D, 0);
1484                 
1485         }
1486
1487         countall();
1488
1489         rightmouse_transform(); /* does undo push! */
1490 }
1491
1492 /* ------------------------------------------------------------------------- */
1493
1494 static int edge_inside_circle(short centx, short centy, short rad, short x1, short y1, short x2, short y2)
1495 {
1496         int radsq= rad*rad;
1497         float v1[2], v2[2], v3[2];
1498         
1499         /* check points in circle itself */
1500         if( (x1-centx)*(x1-centx) + (y1-centy)*(y1-centy) <= radsq ) return 1;
1501         if( (x2-centx)*(x2-centx) + (y2-centy)*(y2-centy) <= radsq ) return 1;
1502         
1503         /* pointdistline */
1504         v3[0]= centx;
1505         v3[1]= centy;
1506         v1[0]= x1;
1507         v1[1]= y1;
1508         v2[0]= x2;
1509         v2[1]= y2;
1510         
1511         if( PdistVL2Dfl(v3, v1, v2) < (float)rad ) return 1;
1512         
1513         return 0;
1514 }
1515
1516 static void do_nurbs_box_select__doSelect(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y)
1517 {
1518         struct { rcti *rect; int select; } *data = userData;
1519
1520         if (BLI_in_rcti(data->rect, x, y)) {
1521                 if (bp) {
1522                         bp->f1 = data->select?(bp->f1|1):(bp->f1&~1);
1523                 } else {
1524                         if (beztindex==0) {
1525                                 bezt->f1 = data->select?(bezt->f1|1):(bezt->f1&~1);
1526                         } else if (beztindex==1) {
1527                                 bezt->f2 = data->select?(bezt->f2|1):(bezt->f2&~1);
1528                         } else {
1529                                 bezt->f3 = data->select?(bezt->f3|1):(bezt->f3&~1);
1530                         }
1531                 }
1532         }
1533 }
1534 static void do_nurbs_box_select(rcti *rect, int select)
1535 {
1536         struct { rcti *rect; int select; } data;
1537
1538         data.rect = rect;
1539         data.select = select;
1540
1541         nurbs_foreachScreenVert(do_nurbs_box_select__doSelect, &data);
1542 }
1543
1544 static void do_lattice_box_select__doSelect(void *userData, BPoint *bp, int x, int y)
1545 {
1546         struct { rcti *rect; int select; } *data = userData;
1547
1548         if (BLI_in_rcti(data->rect, x, y)) {
1549                 bp->f1 = data->select?(bp->f1|1):(bp->f1&~1);
1550         }
1551 }
1552 static void do_lattice_box_select(rcti *rect, int select)
1553 {
1554         struct { rcti *rect; int select, pass, done; } data;
1555
1556         data.rect = rect;
1557         data.select = select;
1558
1559         lattice_foreachScreenVert(do_lattice_box_select__doSelect, &data);
1560 }
1561
1562 static void do_mesh_box_select__doSelectVert(void *userData, EditVert *eve, int x, int y, int index)
1563 {
1564         struct { rcti *rect; short select, pass, done; } *data = userData;
1565
1566         if (BLI_in_rcti(data->rect, x, y)) {
1567                 eve->f = data->select?(eve->f|1):(eve->f&~1);
1568         }
1569 }
1570 static void do_mesh_box_select__doSelectEdge(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index)
1571 {
1572         struct { rcti *rect; short select, pass, done; } *data = userData;
1573
1574         if(EM_check_backbuf(em_solidoffs+index)) {
1575                 if (data->pass==0) {
1576                         if (edge_fully_inside_rect(data->rect, x0, y0, x1, y1)) {
1577                                 EM_select_edge(eed, data->select);
1578                                 data->done = 1;
1579                         }
1580                 } else {
1581                         if (edge_inside_rect(data->rect, x0, y0, x1, y1)) {
1582                                 EM_select_edge(eed, data->select);
1583                         }
1584                 }
1585         }
1586 }
1587 static void do_mesh_box_select__doSelectFace(void *userData, EditFace *efa, int x, int y, int index)
1588 {
1589         struct { rcti *rect; short select, pass, done; } *data = userData;
1590
1591         if (BLI_in_rcti(data->rect, x, y)) {
1592                 EM_select_face_fgon(efa, data->select);
1593         }
1594 }
1595 static void do_mesh_box_select(rcti *rect, int select)
1596 {
1597         struct { rcti *rect; short select, pass, done; } data;
1598         EditMesh *em = G.editMesh;
1599         int bbsel;
1600         
1601         data.rect = rect;
1602         data.select = select;
1603         data.pass = 0;
1604         data.done = 0;
1605
1606         bbsel= EM_init_backbuf_border(rect->xmin, rect->ymin, rect->xmax, rect->ymax);
1607
1608         if(G.scene->selectmode & SCE_SELECT_VERTEX) {
1609                 if (bbsel) {
1610                         EM_backbuf_checkAndSelectVerts(em, select);
1611                 } else {
1612                         mesh_foreachScreenVert(do_mesh_box_select__doSelectVert, &data, 1);
1613                 }
1614         }
1615         if(G.scene->selectmode & SCE_SELECT_EDGE) {
1616                         /* Does both bbsel and non-bbsel versions (need screen cos for both) */
1617
1618                 data.pass = 0;
1619                 mesh_foreachScreenEdge(do_mesh_box_select__doSelectEdge, &data, 0);
1620
1621                 if (data.done==0) {
1622                         data.pass = 1;
1623                         mesh_foreachScreenEdge(do_mesh_box_select__doSelectEdge, &data, 0);
1624                 }
1625         }
1626         
1627         if(G.scene->selectmode & SCE_SELECT_FACE) {
1628                 if(bbsel) {
1629                         EM_backbuf_checkAndSelectFaces(em, select);
1630                 } else {
1631                         mesh_foreachScreenFace(do_mesh_box_select__doSelectFace, &data);
1632                 }
1633         }
1634         
1635         EM_free_backbuf();
1636                 
1637         EM_selectmode_flush();
1638 }
1639
1640 /**
1641  * Does the 'borderselect' command. (Select verts based on selecting with a 
1642  * border: key 'b'). All selecting seems to be done in the get_border part.
1643  */
1644 void borderselect(void)
1645 {
1646         rcti rect;
1647         Base *base;
1648         MetaElem *ml;
1649         unsigned int buffer[MAXPICKBUF];
1650         int a, index;
1651         short hits, val;
1652
1653         if(G.obedit==NULL && (G.f & G_FACESELECT)) {
1654                 face_borderselect();
1655                 return;
1656         }
1657         
1658         setlinestyle(2);
1659         val= get_border(&rect, 3);
1660         setlinestyle(0);
1661         
1662         if(val==0)
1663                 return;
1664         
1665         if(G.obedit) {
1666                 if(G.obedit->type==OB_MESH) {
1667                         do_mesh_box_select(&rect, (val==LEFTMOUSE));
1668                         allqueue(REDRAWVIEW3D, 0);
1669                 }
1670                 else if ELEM(G.obedit->type, OB_CURVE, OB_SURF) {
1671                         do_nurbs_box_select(&rect, val==LEFTMOUSE);
1672                         allqueue(REDRAWVIEW3D, 0);
1673                 }
1674                 else if(G.obedit->type==OB_MBALL) {
1675                         hits= view3d_opengl_select(buffer, MAXPICKBUF, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
1676                         
1677                         ml= editelems.first;
1678                         
1679                         while(ml) {
1680                                 for(a=0; a<hits; a++) {
1681                                         if(ml->selcol1==buffer[ (4 * a) + 3 ]) {
1682                                                 ml->flag |= MB_SCALE_RAD;
1683                                                 if(val==LEFTMOUSE) ml->flag |= SELECT;
1684                                                 else ml->flag &= ~SELECT;
1685                                                 break;
1686                                         }
1687                                         if(ml->selcol2==buffer[ (4 * a) + 3 ]) {
1688                                                 ml->flag &= ~MB_SCALE_RAD;
1689                                                 if(val==LEFTMOUSE) ml->flag |= SELECT;
1690                                                 else ml->flag &= ~SELECT;
1691                                                 break;
1692                                         }
1693                                 }
1694                                 ml= ml->next;
1695                         }
1696                         allqueue(REDRAWVIEW3D, 0);
1697                 }
1698                 else if(G.obedit->type==OB_ARMATURE) {
1699                         EditBone *ebone;
1700                         
1701                         /* clear flag we use to detect point was affected */
1702                         for(ebone= G.edbo.first; ebone; ebone= ebone->next)
1703                                 ebone->flag &= ~BONE_DONE;
1704                         
1705                         hits= view3d_opengl_select(buffer, MAXPICKBUF, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
1706                         
1707                         /* first we only check points inside the border */
1708                         for (a=0; a<hits; a++){
1709                                 index = buffer[(4*a)+3];
1710                                 if (index!=-1) {
1711                                         ebone = BLI_findlink(&G.edbo, index & ~(BONESEL_ANY));
1712                                         if (index & BONESEL_TIP) {
1713                                                 ebone->flag |= BONE_DONE;
1714                                                 if (val==LEFTMOUSE) ebone->flag |= BONE_TIPSEL;
1715                                                 else ebone->flag &= ~BONE_TIPSEL;
1716                                         }
1717                                         
1718                                         if (index & BONESEL_ROOT) {
1719                                                 ebone->flag |= BONE_DONE;
1720                                                 if (val==LEFTMOUSE) ebone->flag |= BONE_ROOTSEL;
1721                                                 else ebone->flag &= ~BONE_ROOTSEL;
1722                                         }
1723                                 }
1724                         }
1725                         
1726                         /* now we have to flush tag from parents... */
1727                         for(ebone= G.edbo.first; ebone; ebone= ebone->next) {
1728                                 if(ebone->parent && (ebone->flag & BONE_CONNECTED)) {
1729                                         if(ebone->parent->flag & BONE_DONE)
1730                                                 ebone->flag |= BONE_DONE;
1731                                 }
1732                         }
1733                         
1734                         /* only select/deselect entire bones when no points where in the rect */
1735                         for (a=0; a<hits; a++){
1736                                 index = buffer[(4*a)+3];
1737                                 if (index!=-1) {
1738                                         ebone = BLI_findlink(&G.edbo, index & ~(BONESEL_ANY));
1739                                         if (index & BONESEL_BONE) {
1740                                                 if(!(ebone->flag & BONE_DONE)) {
1741                                                         if (val==LEFTMOUSE)
1742                                                                 ebone->flag |= (BONE_ROOTSEL|BONE_TIPSEL|BONE_SELECTED);
1743                                                         else
1744                                                                 ebone->flag &= ~(BONE_ROOTSEL|BONE_TIPSEL|BONE_SELECTED);
1745                                                 }
1746                                         }
1747                                 }
1748                         }
1749                         
1750                         allqueue(REDRAWBUTSEDIT, 0);
1751                         allqueue(REDRAWBUTSOBJECT, 0);
1752                         allqueue(REDRAWACTION, 0);
1753                         allqueue(REDRAWVIEW3D, 0);
1754                 }
1755                 else if(G.obedit->type==OB_LATTICE) {
1756                         do_lattice_box_select(&rect, val==LEFTMOUSE);
1757                         allqueue(REDRAWVIEW3D, 0);
1758                 }
1759         }
1760         else {  /* no editmode, unified for bones and objects */
1761                 Bone *bone;
1762                 unsigned int *vbuffer=NULL; /* selection buffer */
1763                 unsigned int *col;                      /* color in buffer      */
1764                 short selecting = 0;
1765
1766                 if (val==LEFTMOUSE)
1767                         selecting = 1;
1768                 
1769                 /* selection buffer now has bones potentially too, so we add MAXPICKBUF */
1770                 vbuffer = MEM_mallocN(4 * (G.totobj+MAXPICKBUF) * sizeof(unsigned int), "selection buffer");
1771                 hits= view3d_opengl_select(vbuffer, 4*(G.totobj+MAXPICKBUF), rect.xmin, rect.ymin, rect.xmax, rect.ymax);
1772                 /*
1773                 LOGIC NOTES (theeth):
1774                 The buffer and ListBase have the same relative order, which makes the selection
1775                 very simple. Loop through both data sets at the same time, if the color
1776                 is the same as the object, we have a hit and can move to the next color
1777                 and object pair, if not, just move to the next object,
1778                 keeping the same color until we have a hit.
1779
1780                 The buffer order is defined by OGL standard, hopefully no stupid GFX card
1781                 does it incorrectly.
1782                 */
1783
1784                 if (hits) { /* no need to loop if there's no hit */
1785                         base= FIRSTBASE;
1786                         col = vbuffer + 3;
1787                         while(base && hits) {
1788                                 Base *next = base->next;
1789                                 if(base->lay & G.vd->lay) {
1790                                         while (base->selcol == (*col & 0xFFFF)) {       /* we got an object */
1791                                                 
1792                                                 if(*col & 0xFFFF0000) {                                 /* we got a bone */
1793                                                         bone = get_indexed_bone(base->object, *col & ~(BONESEL_ANY));
1794                                                         if(bone) {
1795                                                                 if(selecting) {
1796                                                                         bone->flag |= BONE_SELECTED;
1797                                                                         select_actionchannel_by_name(base->object->action, bone->name, 1);
1798                                                                 }
1799                                                                 else {
1800                                                                         bone->flag &= ~(BONE_ACTIVE|BONE_SELECTED);
1801                                                                         select_actionchannel_by_name(base->object->action, bone->name, 0);
1802                                                                 }
1803                                                         }
1804                                                 }
1805                                                 else {
1806                                                         if (selecting)
1807                                                                 select_base_v3d(base, BA_SELECT);
1808                                                         else
1809                                                                 select_base_v3d(base, BA_DESELECT);
1810
1811                                                         base->object->flag= base->flag;
1812                                                 }
1813
1814                                                 col+=4; /* next color */
1815                                                 hits--;
1816                                                 if(hits==0) break;
1817                                         }
1818                                 }
1819                                 
1820                                 base= next;
1821                         }
1822                 }
1823                 /* frontbuffer flush */
1824                 bglFlush();
1825
1826                 MEM_freeN(vbuffer);
1827                 
1828                 allqueue(REDRAWDATASELECT, 0);
1829                 allqueue(REDRAWBUTSLOGIC, 0);
1830                 allqueue(REDRAWNLA, 0);
1831         }
1832
1833         countall();
1834         
1835         allqueue(REDRAWBUTSOBJECT, 0);
1836         allqueue(REDRAWVIEW3D, 0);
1837         allqueue(REDRAWINFO, 0);
1838
1839         BIF_undo_push("Border select");
1840         
1841 } /* end of borderselect() */
1842
1843 /* ------------------------------------------------------------------------- */
1844
1845 /** The following functions are quick & dirty callback functions called
1846   * on the Circle select function (press B twice in Editmode)
1847   * They were torn out of the circle_select to make the latter more reusable
1848   * The callback version of circle_select (called circle_selectCB) was moved
1849   * to edit.c because of it's (wanted) generality.
1850
1851         XXX These callback functions are still dirty, because they call globals... 
1852   */
1853
1854 static void mesh_selectionCB__doSelectVert(void *userData, EditVert *eve, int x, int y, int index)
1855 {
1856         struct { short select, mval[2]; float radius; } *data = userData;
1857         int mx = x - data->mval[0], my = y - data->mval[1];
1858         float r = sqrt(mx*mx + my*my);
1859
1860         if (r<=data->radius) {
1861                 eve->f = data->select?(eve->f|1):(eve->f&~1);
1862         }
1863 }
1864 static void mesh_selectionCB__doSelectEdge(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index)
1865 {
1866         struct { short select, mval[2]; float radius; } *data = userData;
1867
1868         if (edge_inside_circle(data->mval[0], data->mval[1], (short) data->radius, x0, y0, x1, y1)) {
1869                 EM_select_edge(eed, data->select);
1870         }
1871 }
1872 static void mesh_selectionCB__doSelectFace(void *userData, EditFace *efa, int x, int y, int index)
1873 {
1874         struct { short select, mval[2]; float radius; } *data = userData;
1875         int mx = x - data->mval[0], my = y - data->mval[1];
1876         float r = sqrt(mx*mx + my*my);
1877
1878         if (r<=data->radius) {
1879                 EM_select_face_fgon(efa, data->select);
1880         }
1881 }
1882 static void mesh_selectionCB(int selecting, Object *editobj, short *mval, float rad)
1883 {
1884         struct { short select, mval[2]; float radius; } data;
1885         EditMesh *em = G.editMesh;
1886         int bbsel;
1887
1888         if(!G.obedit && (G.f&G_FACESELECT)) {
1889                 Mesh *me = get_mesh(OBACT);
1890
1891                 if (me) {
1892                         em_vertoffs= me->totface+1;     /* max index array */
1893
1894                         bbsel= EM_init_backbuf_circle(mval[0], mval[1], (short)(rad+1.0));
1895                         EM_backbuf_checkAndSelectTFaces(me, selecting==LEFTMOUSE);
1896                         EM_free_backbuf();
1897
1898                         object_tface_flags_changed(OBACT, 0);
1899                 }
1900
1901                 return;
1902         }
1903
1904         bbsel= EM_init_backbuf_circle(mval[0], mval[1], (short)(rad+1.0));
1905         
1906         data.select = (selecting==LEFTMOUSE);
1907         data.mval[0] = mval[0];
1908         data.mval[1] = mval[1];
1909         data.radius = rad;
1910
1911         if(G.scene->selectmode & SCE_SELECT_VERTEX) {
1912                 if(bbsel) {
1913                         EM_backbuf_checkAndSelectVerts(em, selecting==LEFTMOUSE);
1914                 } else {
1915                         mesh_foreachScreenVert(mesh_selectionCB__doSelectVert, &data, 1);
1916                 }
1917         }
1918
1919         if(G.scene->selectmode & SCE_SELECT_EDGE) {
1920                 if (bbsel) {
1921                         EM_backbuf_checkAndSelectEdges(em, selecting==LEFTMOUSE);
1922                 } else {
1923                         mesh_foreachScreenEdge(mesh_selectionCB__doSelectEdge, &data, 0);
1924                 }
1925         }
1926         
1927         if(G.scene->selectmode & SCE_SELECT_FACE) {
1928                 if(bbsel) {
1929                         EM_backbuf_checkAndSelectFaces(em, selecting==LEFTMOUSE);
1930                 } else {
1931                         mesh_foreachScreenFace(mesh_selectionCB__doSelectFace, &data);
1932                 }
1933         }
1934
1935         EM_free_backbuf();
1936         EM_selectmode_flush();
1937 }
1938
1939
1940 static void nurbscurve_selectionCB__doSelect(void *userData, Nurb *nu, BPoint *bp, BezTriple *bezt, int beztindex, int x, int y)
1941 {
1942         struct { short select, mval[2]; float radius; } *data = userData;
1943         int mx = x - data->mval[0], my = y - data->mval[1];
1944         float r = sqrt(mx*mx + my*my);
1945
1946         if (r<=data->radius) {
1947                 if (bp) {
1948                         bp->f1 = data->select?(bp->f1|1):(bp->f1&~1);
1949                 } else {
1950                         if (beztindex==0) {
1951                                 bezt->f1 = data->select?(bezt->f1|1):(bezt->f1&~1);
1952                         } else if (beztindex==1) {
1953                                 bezt->f2 = data->select?(bezt->f2|1):(bezt->f2&~1);
1954                         } else {
1955                                 bezt->f3 = data->select?(bezt->f3|1):(bezt->f3&~1);
1956                         }
1957                 }
1958         }
1959 }
1960 static void nurbscurve_selectionCB(int selecting, Object *editobj, short *mval, float rad)
1961 {
1962         struct { short select, mval[2]; float radius; } data;
1963
1964         data.select = (selecting==LEFTMOUSE);
1965         data.mval[0] = mval[0];
1966         data.mval[1] = mval[1];
1967         data.radius = rad;
1968
1969         nurbs_foreachScreenVert(nurbscurve_selectionCB__doSelect, &data);
1970 }
1971
1972
1973 static void latticecurve_selectionCB__doSelect(void *userData, BPoint *bp, int x, int y)
1974 {
1975         struct { short select, mval[2]; float radius; } *data = userData;
1976         int mx = x - data->mval[0], my = y - data->mval[1];
1977         float r = sqrt(mx*mx + my*my);
1978
1979         if (r<=data->radius) {
1980                 bp->f1 = data->select?(bp->f1|1):(bp->f1&~1);
1981         }
1982 }
1983 static void lattice_selectionCB(int selecting, Object *editobj, short *mval, float rad)
1984 {
1985         struct { short select, mval[2]; float radius; } data;
1986
1987         data.select = (selecting==LEFTMOUSE);
1988         data.mval[0] = mval[0];
1989         data.mval[1] = mval[1];
1990         data.radius = rad;
1991
1992         lattice_foreachScreenVert(latticecurve_selectionCB__doSelect, &data);
1993 }
1994
1995 /** Callbacks for selection in Editmode */
1996
1997 void obedit_selectionCB(short selecting, Object *editobj, short *mval, float rad) 
1998 {
1999         switch(editobj->type) {         
2000         case OB_MESH:
2001                 mesh_selectionCB(selecting, editobj, mval, rad);
2002                 break;
2003         case OB_CURVE:
2004         case OB_SURF:
2005                 nurbscurve_selectionCB(selecting, editobj, mval, rad);
2006                 break;
2007         case OB_LATTICE:
2008                 lattice_selectionCB(selecting, editobj, mval, rad);
2009                 break;
2010         default:
2011                 return;
2012         }
2013
2014         draw_sel_circle(0, 0, 0, 0, 0); /* signal */
2015         force_draw(0);
2016 }
2017
2018 void set_render_border(void)
2019 {
2020         rcti rect;
2021         short val;
2022         
2023         val= get_border(&rect, 3);
2024         if(val) {
2025                 rctf vb;
2026
2027                 calc_viewborder(G.vd, &vb);
2028
2029                 G.scene->r.border.xmin= ((float)rect.xmin-vb.xmin)/(vb.xmax-vb.xmin);
2030                 G.scene->r.border.ymin= ((float)rect.ymin-vb.ymin)/(vb.ymax-vb.ymin);
2031                 G.scene->r.border.xmax= ((float)rect.xmax-vb.xmin)/(vb.xmax-vb.xmin);
2032                 G.scene->r.border.ymax= ((float)rect.ymax-vb.ymin)/(vb.ymax-vb.ymin);
2033                 
2034                 CLAMP(G.scene->r.border.xmin, 0.0, 1.0);
2035                 CLAMP(G.scene->r.border.ymin, 0.0, 1.0);
2036                 CLAMP(G.scene->r.border.xmax, 0.0, 1.0);
2037                 CLAMP(G.scene->r.border.ymax, 0.0, 1.0);
2038                 
2039                 allqueue(REDRAWVIEWCAM, 1);
2040                 /* if it was not set, we do this */
2041                 G.scene->r.mode |= R_BORDER;
2042                 allqueue(REDRAWBUTSSCENE, 1);
2043         }
2044 }
2045
2046 void view3d_border_zoom(void)
2047 {
2048         /* Zooms in on a border drawn by the user */
2049         rcti rect;
2050         short val;
2051         float dvec[3], vb[2], xscale, yscale, scale;
2052         
2053         /* doesn't work fine for perspective */
2054         if(G.vd->persp==1)
2055                 return;
2056         
2057         val = get_border(&rect, 3); //box select input
2058         if(val)
2059         {
2060                 /* find the current window width and height */
2061                 vb[0] = G.vd->area->winx;
2062                 vb[1] = G.vd->area->winy;
2063                 
2064                 /* convert the drawn rectangle into 3d space */
2065                 initgrabz(-G.vd->ofs[0], -G.vd->ofs[1], -G.vd->ofs[2]);
2066                 window_to_3d(dvec, (rect.xmin+rect.xmax-vb[0])/2, (rect.ymin+rect.ymax-vb[1])/2);
2067                 
2068                 /* center the view to the center of the rectangle */
2069                 VecSubf(G.vd->ofs, G.vd->ofs, dvec);
2070                 
2071                 /* work out the ratios, so that everything selected fits when we zoom */
2072                 xscale = ((rect.xmax-rect.xmin)/vb[0]);
2073                 yscale = ((rect.ymax-rect.ymin)/vb[1]);
2074                 scale = (xscale >= yscale)?xscale:yscale;
2075                 
2076                 /* zoom in as required, or as far as we can go */
2077                 G.vd->dist = ((G.vd->dist*scale) >= 0.001*G.vd->grid)? G.vd->dist*scale:0.001*G.vd->grid;
2078         }
2079 }
2080
2081 void fly(void)
2082 {
2083         /*
2084         fly mode - Shift+F
2085         a fly loop where the user can move move the view as if they are flying
2086         */
2087         float speed=0.0, /* the speed the view is moving per redraw */
2088         mat[3][3], /* 3x3 copy of the view matrix so we can move allong the view axis */
2089         dvec[3]={0,0,0}, /* this is the direction thast added to the view offset per redraw */
2090         dvec_old[3]={0,0,0}, /* old for some lag */
2091         dvec_tmp[3]={0,0,0}, /* old for some lag */
2092         dvec_lag=0.0, /* old for some lag */
2093         
2094         /* Camera Uprighting variables */
2095         roll, /* similar to the angle between the camera's up and the Z-up, but its very rough so just roll*/
2096         upvec[3]={0,0,0}, /* stores the view's up vector */
2097         
2098         dist_backup, /* backup the views distance since we use a zero dist for fly mode */
2099         rot_backup[4], /* backup the views quat incase the user cancels flying in non camera mode */
2100         ofs_backup[3], /* backup the views offset incase the user cancels flying in non camera mode */
2101         moffset[2], /* mouse offset from the views center */
2102         tmp_quat[4], /* used for rotating the view */
2103         winxf, winyf, /* scale the mouse movement by this value - scales mouse movement to the view size */
2104         time_redraw, time_redraw_clamped; /*time how fast it takes for us to redraw, this is so simple scenes dont fly too fast */
2105         
2106         
2107         double time_current, time_lastdraw;
2108         
2109         short val, /* used for toets to see if a buttons pressed */
2110         cent_orig[2], /* view center */
2111         cent[2], /* view center modified */
2112         mval[2], /* mouse location */
2113         action=0, /* while zero stay in fly mode and wait for action, also used to see if we accepted or canceled 1:ok 2:Cancel */
2114         xmargin, ymargin; /* x and y margin are define the safe area where the mouses movement wont rotate the view */
2115         unsigned short
2116         toets; /* for reading the event */
2117         unsigned char
2118         apply_rotation= 1, /* if the user presses shift they can look about without movinf the direction there looking*/
2119         axis= 2, /* Axis index to move allong by default Z to move allong the view */
2120         persp_backup, /* remember if were ortho or not, only used for restoring the view if it was a ortho view */
2121         pan_view=0; /* if true, pan the view instead of rotating */
2122         
2123         /* relative view axis locking - xlock, zlock
2124         0; disabled
2125         1; enabled but not checking because mouse hasnt moved outside the margin since locking was checked an not needed
2126            when the mouse moves, locking is set to 2 so checks are done.
2127         2; mouse moved and checking needed, if no view altering is donem its changed back to 1 */
2128         short xlock=0, zlock=0;
2129         float xlock_momentum=0.0f, zlock_momentum=0.0f; /* nicer dynamics */
2130         
2131         /* for recording */
2132         int playing_anim = has_screenhandler(G.curscreen, SCREEN_HANDLER_ANIM);
2133         int cfra = -1; /*so the first frame always has a key added */
2134         char *actname="";
2135         
2136         
2137         if(curarea->spacetype!=SPACE_VIEW3D) return;
2138                 
2139         if(G.vd->persp==2 && G.vd->camera->id.lib) {
2140                 error("Cannot fly a camera from an external library");
2141                 return;
2142         }
2143         
2144         if(G.vd->ob_centre) {
2145                 error("Cannot fly when the view is locked to an object");
2146                 return;
2147         }
2148         
2149         
2150         /* detect weather to start with Z locking */
2151         upvec[0]=1; upvec[1]=0; upvec[2]=0;
2152         Mat3CpyMat4(mat, G.vd->viewinv);
2153         Mat3MulVecfl(mat, upvec);
2154         if (fabs(upvec[2]) < 0.1)
2155                 zlock = 1;
2156         upvec[0]=0; upvec[1]=0; upvec[2]=0;
2157         
2158         persp_backup= G.vd->persp;
2159         dist_backup= G.vd->dist;
2160         if (G.vd->persp==2) { /* Camera */
2161                 if(G.vd->camera->constraints.first) {
2162                         error("Cannot fly an object with constraints");
2163                         return;
2164                 }
2165                 
2166                 /* store the origoinal camera loc and rot */
2167                 VECCOPY(ofs_backup, G.vd->camera->loc);
2168                 VECCOPY(rot_backup, G.vd->camera->rot);
2169                 
2170                 where_is_object(G.vd->camera);
2171                 VECCOPY(G.vd->ofs, G.vd->camera->obmat[3]);
2172                 VecMulf(G.vd->ofs, -1.0f); /*flip the vector*/
2173                 
2174                 G.vd->dist=0.0;
2175                 G.vd->viewbut=0;
2176                 
2177                 /* used for recording */
2178                 if(G.vd->camera->ipoflag & OB_ACTION_OB)
2179                         actname= "Object";
2180                 
2181         } else {
2182                 /* perspective or ortho */
2183                 if (G.vd->persp==0)
2184                         G.vd->persp= 1; /*if ortho projection, make perspective */
2185                 QUATCOPY(rot_backup, G.vd->viewquat);
2186                 VECCOPY(ofs_backup, G.vd->ofs);
2187                 G.vd->dist= 0.0;
2188                 
2189                 upvec[2]=dist_backup; /*x and y are 0*/
2190                 Mat3MulVecfl(mat, upvec);
2191                 VecSubf(G.vd->ofs, G.vd->ofs, upvec);
2192                 /*Done with correcting for the dist*/
2193         }
2194         
2195         /* the dist defines a vector that is infront of the offset
2196         to rotate the view about.
2197         this is no good for fly mode because we
2198         want to rotate about the viewers centre.
2199         but to correct the dist removal we must
2200         alter offset so the view dosent jump. */
2201         
2202         xmargin= (short)((float)(curarea->winx)/20.0);
2203         ymargin= (short)((float)(curarea->winy)/20.0);
2204         
2205         cent_orig[0]= curarea->winrct.xmin+(curarea->winx)/2;
2206         cent_orig[1]= curarea->winrct.ymin+(curarea->winy)/2;
2207         
2208         warp_pointer(cent_orig[0], cent_orig[1]);
2209
2210         /* we have to rely on events to give proper mousecoords after a warp_pointer */
2211         mval[0]= cent[0]=  (curarea->winx)/2;
2212         mval[1]= cent[1]=  (curarea->winy)/2;
2213         /* window size minus margin - use this to get the mouse range for rotation */
2214         winxf= (float)(curarea->winx)-(xmargin*2);
2215         winyf= (float)(curarea->winy)-(ymargin*2); 
2216         
2217         
2218         time_lastdraw= PIL_check_seconds_timer();
2219         
2220         G.vd->flag2 |= V3D_FLYMODE; /* so we draw the corner margins */
2221         scrarea_do_windraw(curarea);
2222         screen_swapbuffers();
2223         
2224         while(action==0) { /* keep flying, no acton taken */
2225                 while(qtest()) {
2226                         toets= extern_qread(&val);
2227                         
2228                         if(val) {
2229                                 if(toets==MOUSEY) getmouseco_areawin(mval);
2230                                 else if(toets==ESCKEY || toets==RIGHTMOUSE) {
2231                                         action= 2; /* Canceled */
2232                                         break;
2233                                 } else if(toets==SPACEKEY || toets==LEFTMOUSE) {
2234                                         action= 1; /* Accepted */
2235                                         break;
2236                                 } else if(toets==PADPLUSKEY || toets==EQUALKEY || toets==WHEELUPMOUSE) {
2237                                         if (speed<0) speed=0;
2238                                         else speed+= G.vd->grid;
2239                                 } else if(toets==PADMINUS || toets==MINUSKEY || toets==WHEELDOWNMOUSE) {
2240                                         if (speed>0) speed=0;
2241                                         else speed-= G.vd->grid;
2242                                 
2243                                 } else if (toets==MIDDLEMOUSE) {
2244                                         /* make it so the camera direction dosent follow the view
2245                                         good for flying backwards! - Only when MMB is held */
2246                                         
2247                                         /*apply_rotation=0;*/
2248                                         pan_view= 1;
2249                                         
2250                                 /* impliment WASD keys */
2251                                 } else if(toets==WKEY) {
2252                                         if (speed<0) speed=-speed; /* flip speed rather then stopping, game like motion */
2253                                         else speed+= G.vd->grid; /* increse like mousewheel if were alredy moving in that difection*/
2254                                         axis= 2;
2255                                 } else if(toets==SKEY) { /*SAME as above but flipped */
2256                                         if (speed>0) speed=-speed;
2257                                         else speed-= G.vd->grid;
2258                                         axis= 2;
2259                                 
2260                                 } else if(toets==AKEY) {
2261                                         if (speed<0) speed=-speed;
2262                                         axis= 0;
2263                                 } else if(toets==DKEY) {
2264                                         if (speed>0) speed=-speed;
2265                                         axis= 0;
2266                                 } else if(toets==FKEY) {
2267                                         if (speed<0) speed=-speed;
2268                                         axis= 1;
2269                                 } else if(toets==RKEY) {
2270                                         if (speed>0) speed=-speed;
2271                                         axis= 1;
2272                                 
2273                                 /* axis locking */
2274                                 } else if(toets==XKEY) {
2275                                         if (xlock) xlock=0;
2276                                         else {
2277                                                 xlock = 2;
2278                                                 xlock_momentum = 0.0;
2279                                         }
2280                                 } else if(toets==ZKEY) {
2281                                         if (zlock) zlock=0;
2282                                         else {
2283                                                 zlock = 2;
2284                                                 zlock_momentum = 0.0;
2285                                         }
2286                                 }
2287                                 
2288                         } else {
2289                                 /* mouse buttons lifted */
2290                                 if (toets==MIDDLEMOUSE && pan_view) {
2291                                         /*apply_rotation=1;*/
2292                                         warp_pointer(cent_orig[0], cent_orig[1]);
2293                                         pan_view= 0;
2294                                 }
2295                         }
2296                 }
2297                 if(action != 0) break;
2298                 
2299                 moffset[0]= mval[0]-cent[0];
2300                 moffset[1]= mval[1]-cent[1];
2301                 
2302                 /* enforce a view margin */
2303                 if (moffset[0]>xmargin)         moffset[0]-=xmargin;
2304                 else if (moffset[0]<-xmargin)moffset[0]+=xmargin;
2305                 else                                    moffset[0]=0;
2306
2307                 if (moffset[1]>ymargin)         moffset[1]-=ymargin;
2308                 else if (moffset[1]<-ymargin)moffset[1]+=ymargin;
2309                 else                                    moffset[1]=0;
2310                 
2311                 /* scale the mouse offset so the distance the mouse moves isnt linear */
2312                 if (moffset[0]) {
2313                         moffset[0]= moffset[0]/winxf;
2314                         moffset[0]= moffset[0]*fabs(moffset[0]);
2315                 }
2316                 
2317                 if (moffset[1]) {
2318                         moffset[1]= moffset[1]/winyf;
2319                         moffset[1]= moffset[1]*fabs(moffset[1]);
2320                 }
2321                 
2322                 /* Should we redraw? */
2323                 if(speed!=0.0 || moffset[0] || moffset[1] || zlock || xlock || dvec[0] || dvec[1] || dvec[2] ) {
2324                         
2325                         time_current= PIL_check_seconds_timer();
2326                         time_redraw= (float)(time_current-time_lastdraw);
2327                         time_redraw_clamped= MIN2(0.05, time_redraw); /* clamt the redraw time to avoid jitter in roll correction */
2328                         time_lastdraw= time_current;
2329                         /*fprintf(stderr, "%f\n", time_redraw);*/ /* 0.002 is a small redraw 0.02 is larger */
2330                         
2331                         /* Scale the time to use shift to scale the speed down- just like
2332                         shift slows many other areas of blender down */
2333                         if (G.qual & LR_SHIFTKEY)
2334                                 speed= speed * (1-time_redraw_clamped);
2335                         
2336                         Mat3CpyMat4(mat, G.vd->viewinv);
2337                         
2338                         if (pan_view) {
2339                                 /* pan only */
2340                                 dvec_tmp[0]= -moffset[0];
2341                                 dvec_tmp[1]= -moffset[1];
2342                                 dvec_tmp[2]= 0;
2343                                 /* z axis can stay teh same, just keep costing */
2344                                 
2345                                 Mat3MulVecfl(mat, dvec_tmp);
2346                                 VecMulf(dvec_tmp, time_redraw*200.0 * G.vd->grid);
2347                                 
2348                         } else {
2349                                 /* rotate about the X axis- look up/down */
2350                                 if (moffset[1]) {
2351                                         upvec[0]=1;
2352                                         upvec[1]=0;
2353                                         upvec[2]=0;
2354                                         Mat3MulVecfl(mat, upvec);
2355                                         VecRotToQuat( upvec, (float)moffset[1]*-time_redraw*20, tmp_quat); /* Rotate about the relative up vec */
2356                                         QuatMul(G.vd->viewquat, G.vd->viewquat, tmp_quat);
2357                                         
2358                                         if (xlock) xlock = 2; /*check for rotation*/
2359                                         if (zlock) zlock = 2;
2360                                         xlock_momentum= 0.0;
2361                                 }
2362                                 
2363                                 /* rotate about the Y axis- look left/right */
2364                                 if (moffset[0]) {
2365                                         
2366                                         if (zlock) {
2367                                                 upvec[0]=0;
2368                                                 upvec[1]=0;
2369                                                 upvec[2]=1;
2370                                         } else {
2371                                                 upvec[0]=0;
2372                                                 upvec[1]=1;
2373                                                 upvec[2]=0;
2374                                                 Mat3MulVecfl(mat, upvec);
2375                                         }
2376                                                 
2377                                         VecRotToQuat( upvec, (float)moffset[0]*time_redraw*20, tmp_quat); /* Rotate about the relative up vec */
2378                                         QuatMul(G.vd->viewquat, G.vd->viewquat, tmp_quat);
2379                                         
2380                                         if (xlock) xlock = 2;/*check for rotation*/
2381                                         if (zlock) zlock = 2;
2382                                 }
2383                                 
2384                                 if (zlock==2) {
2385                                         upvec[0]=1;
2386                                         upvec[1]=0;
2387                                         upvec[2]=0;
2388                                         Mat3MulVecfl(mat, upvec);
2389
2390                                         /*make sure we have some z rolling*/
2391                                         if (fabs(upvec[2]) > 0.00001) {
2392                                                 roll= upvec[2]*5;
2393                                                 upvec[0]=0; /*rotate the view about this axis*/
2394                                                 upvec[1]=0;
2395                                                 upvec[2]=1;
2396                                                 
2397                                                 Mat3MulVecfl(mat, upvec);
2398                                                 VecRotToQuat( upvec, roll*time_redraw_clamped*zlock_momentum*0.1, tmp_quat); /* Rotate about the relative up vec */
2399                                                 QuatMul(G.vd->viewquat, G.vd->viewquat, tmp_quat);
2400                                                 
2401                                                 zlock_momentum += 0.05;
2402                                         } else {
2403                                                 zlock=1; /* dont check until the view rotates again */
2404                                                 zlock_momentum= 0.0;
2405                                         }
2406                                 }
2407                                 
2408                                 if (xlock==2 && moffset[1]==0) { /*only apply xcorrect when mouse isnt applying x rot*/
2409                                         upvec[0]=0;
2410                                         upvec[1]=0;
2411                                         upvec[2]=1;
2412                                         Mat3MulVecfl(mat, upvec);
2413                                         /*make sure we have some z rolling*/
2414                                         if (fabs(upvec[2]) > 0.00001) {
2415                                                 roll= upvec[2]*-5;
2416                                                 
2417                                                 upvec[0]=1; /*rotate the view about this axis*/
2418                                                 upvec[1]=0;
2419                                                 upvec[2]=0;
2420                                                 
2421                                                 Mat3MulVecfl(mat, upvec);
2422                                                 
2423                                                 VecRotToQuat( upvec, roll*time_redraw_clamped*xlock_momentum*0.1, tmp_quat); /* Rotate about the relative up vec */
2424                                                 QuatMul(G.vd->viewquat, G.vd->viewquat, tmp_quat);
2425                                                 
2426                                                 xlock_momentum += 0.05;
2427                                         } else {
2428                                                 xlock=1; /* see above */
2429                                                 xlock_momentum= 0.0;
2430                                         }
2431                                 }
2432
2433
2434                                 if (apply_rotation) {
2435                                         /* Normal operation */
2436                                         /* define dvec, view direction vector */
2437                                         dvec_tmp[0]= dvec_tmp[1]= dvec_tmp[2]= 0;
2438                                         /* move along the current axis */
2439                                         dvec_tmp[axis]= 1.0f;
2440                                         
2441                                         Mat3MulVecfl(mat, dvec_tmp);
2442                                         
2443                                         VecMulf(dvec_tmp, speed*time_redraw*0.5);
2444                                 }
2445                         }
2446                         
2447                         /* impose a directional lag */
2448                         dvec_lag = 1.0/(1+(time_redraw*5));
2449                         dvec[0] = dvec_tmp[0]*(1-dvec_lag) + dvec_old[0]*dvec_lag;
2450                         dvec[1] = dvec_tmp[1]*(1-dvec_lag) + dvec_old[1]*dvec_lag;
2451                         dvec[2] = dvec_tmp[2]*(1-dvec_lag) + dvec_old[2]*dvec_lag;
2452                         
2453                         VecAddf(G.vd->ofs, G.vd->ofs, dvec);
2454                         if (zlock && xlock)
2455                                 headerprint("FlyKeys  Speed:(+/- | Wheel),  Upright Axis:X  on/Z on,   Slow:Shift,  Direction:WASDRF,  Ok:LMB,  Pan:MMB,  Cancel:RMB");
2456                         else if (zlock) 
2457                                 headerprint("FlyKeys  Speed:(+/- | Wheel),  Upright Axis:X off/Z on,   Slow:Shift,  Direction:WASDRF,  Ok:LMB,  Pan:MMB,  Cancel:RMB");
2458                         else if (xlock)
2459                                 headerprint("FlyKeys  Speed:(+/- | Wheel),  Upright Axis:X  on/Z off,  Slow:Shift,  Direction:WASDRF,  Ok:LMB,  Pan:MMB,  Cancel:RMB");
2460                         else
2461                                 headerprint("FlyKeys  Speed:(+/- | Wheel),  Upright Axis:X off/Z off,  Slow:Shift,  Direction:WASDRF,  Ok:LMB,  Pan:MMB,  Cancel:RMB");
2462                         
2463                         do_screenhandlers(G.curscreen); /* advance the next frame */
2464                         
2465                         /* we are in camera view so apply the view ofs and quat to the view matrix and set the camera to teh view */
2466                         if (G.vd->persp==2) {
2467                                 G.vd->persp= 1; /*set this so setviewmatrixview3d uses the ofs and quat instead of the camera */
2468                                 setviewmatrixview3d();
2469                                 setcameratoview3d();
2470                                 G.vd->persp= 2;
2471                                 
2472                                 /* record the motion */
2473                                 if (G.flags & G_RECORDKEYS && (!playing_anim || cfra != G.scene->r.cfra)) {
2474                                         cfra = G.scene->r.cfra;
2475                                         
2476                                         if (xlock || zlock || moffset[0] || moffset[1]) {
2477                                                 insertkey(&G.vd->camera->id, ID_OB, actname, NULL, OB_ROT_X);
2478                                                 insertkey(&G.vd->camera->id, ID_OB, actname, NULL, OB_ROT_Y);
2479                                                 insertkey(&G.vd->camera->id, ID_OB, actname, NULL, OB_ROT_Z);
2480                                         }
2481                                         if (speed) {
2482                                                 insertkey(&G.vd->camera->id, ID_OB, actname, NULL, OB_LOC_X);
2483                                                 insertkey(&G.vd->camera->id, ID_OB, actname, NULL, OB_LOC_Y);
2484                                                 insertkey(&G.vd->camera->id, ID_OB, actname, NULL, OB_LOC_Z);
2485                                         }
2486                                 }
2487                         }
2488                         scrarea_do_windraw(curarea);
2489                         screen_swapbuffers();
2490                 } else 
2491                         /*were not redrawing but we need to update the time else the view will jump */
2492                         time_lastdraw= PIL_check_seconds_timer();
2493                 /* end drawing */
2494                 VECCOPY(dvec_old, dvec);
2495         }
2496         
2497         G.vd->dist= dist_backup;
2498         
2499         /* Revert to original view? */ 
2500         if (action == 2) { /* action == 2 means the user pressed Esc of RMB, and not to apply view to camera */
2501                 if (persp_backup==2) { /* a camera view */
2502                         G.vd->viewbut=1;
2503                         VECCOPY(G.vd->camera->loc, ofs_backup);
2504                         VECCOPY(G.vd->camera->rot, rot_backup);
2505                         DAG_object_flush_update(G.scene, G.vd->camera, OB_RECALC_OB);
2506                 } else {
2507                         /* Non Camera we need to reset the view back to the original location bacause the user canceled*/
2508                         QUATCOPY(G.vd->viewquat, rot_backup);
2509                         VECCOPY(G.vd->ofs, ofs_backup);
2510                         G.vd->persp= persp_backup;
2511                 }
2512         }
2513         else if (persp_backup==2) {     /* camera */
2514                 float mat3[3][3];
2515                 Mat3CpyMat4(mat3, G.vd->camera->obmat);
2516                 Mat3ToCompatibleEul(mat3, G.vd->camera->rot, rot_backup);
2517                 
2518                 DAG_object_flush_update(G.scene, G.vd->camera, OB_RECALC_OB);
2519                 
2520                 if (G.flags & G_RECORDKEYS) {
2521                         allqueue(REDRAWIPO, 0);
2522                         allspace(REMAKEIPO, 0);
2523                         allqueue(REDRAWNLA, 0);
2524                         allqueue(REDRAWTIME, 0);
2525                 }
2526         }
2527         else { /* not camera */
2528                 /* Apply the fly mode view */
2529                 /*restore the dist*/
2530                 upvec[0]= upvec[1]= 0;
2531                 upvec[2]=dist_backup; /*x and y are 0*/
2532                 Mat3CpyMat4(mat, G.vd->viewinv);
2533                 Mat3MulVecfl(mat, upvec);
2534                 VecAddf(G.vd->ofs, G.vd->ofs, upvec);
2535                 /*Done with correcting for the dist */
2536         }
2537         
2538         G.vd->flag2 &= ~V3D_FLYMODE;
2539         allqueue(REDRAWVIEW3D, 0);
2540         BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT); /* not working at the moment not sure why */
2541 }
2542
2543 void view3d_edit_clipping(View3D *v3d)
2544 {
2545         
2546         if(v3d->flag & V3D_CLIPPING) {
2547                 v3d->flag &= ~V3D_CLIPPING;
2548                 scrarea_queue_winredraw(curarea);
2549                 if(v3d->clipbb) MEM_freeN(v3d->clipbb);
2550                 v3d->clipbb= NULL;
2551         }
2552         else {
2553                 rcti rect;
2554                 double mvmatrix[16];
2555                 double projmatrix[16];
2556                 double xs, ys, p[3];
2557                 GLint viewport[4];
2558                 short val;
2559                 
2560                 /* get border in window coords */
2561                 setlinestyle(2);
2562                 val= get_border(&rect, 3);
2563                 setlinestyle(0);
2564                 if(val==0) return;
2565                 
2566                 v3d->flag |= V3D_CLIPPING;
2567                 v3d->clipbb= MEM_mallocN(sizeof(BoundBox), "clipbb");
2568                 
2569                 /* convert border to 3d coordinates */
2570                 
2571                 /* Get the matrices needed for gluUnProject */
2572                 glGetIntegerv(GL_VIEWPORT, viewport);
2573                 glGetDoublev(GL_MODELVIEW_MATRIX, mvmatrix);
2574                 glGetDoublev(GL_PROJECTION_MATRIX, projmatrix);
2575
2576                 /* near zero floating point values can give issues with gluUnProject
2577                    in side view on some implementations */
2578                 if(fabs(mvmatrix[0]) < 1e-6) mvmatrix[0]= 0.0;
2579                 if(fabs(mvmatrix[5]) < 1e-6) mvmatrix[5]= 0.0;
2580                 
2581                 /* Set up viewport so that gluUnProject will give correct values */
2582                 viewport[0] = 0;
2583                 viewport[1] = 0;
2584                 
2585                 /* four clipping planes and bounding volume */
2586                 /* first do the bounding volume */
2587                 for(val=0; val<4; val++) {
2588                         
2589                         xs= (val==0||val==3)?rect.xmin:rect.xmax;
2590                         ys= (val==0||val==1)?rect.ymin:rect.ymax;
2591                         
2592                         gluUnProject(xs, ys, 0.0, mvmatrix, projmatrix, viewport, &p[0], &p[1], &p[2]);
2593                         VECCOPY(v3d->clipbb->vec[val], p);
2594                         
2595                         gluUnProject(xs, ys, 1.0, mvmatrix, projmatrix, viewport, &p[0], &p[1], &p[2]);
2596                         VECCOPY(v3d->clipbb->vec[4+val], p);
2597                 }
2598                 
2599                 /* then plane equations */
2600                 for(val=0; val<4; val++) {
2601                         
2602                         CalcNormFloat(v3d->clipbb->vec[val], v3d->clipbb->vec[val==3?0:val+1], v3d->clipbb->vec[val+4],
2603                                                   v3d->clip[val]); 
2604                         
2605                         v3d->clip[val][3]= - v3d->clip[val][0]*v3d->clipbb->vec[val][0] 
2606                                                            - v3d->clip[val][1]*v3d->clipbb->vec[val][1] 
2607                                                            - v3d->clip[val][2]*v3d->clipbb->vec[val][2];
2608                 }
2609         }
2610 }
2611