d8982fb68ca8848085af274f9f7d569dda8131ec
[blender.git] / source / blender / editors / space_view3d / view3d_view.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL 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. 
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * The Original Code is Copyright (C) 2008 Blender Foundation.
21  * All rights reserved.
22  *
23  * 
24  * Contributor(s): Blender Foundation
25  *
26  * ***** END GPL LICENSE BLOCK *****
27  */
28
29 #include <string.h>
30 #include <stdio.h>
31 #include <math.h>
32 #include <float.h>
33
34 #include "DNA_anim_types.h"
35 #include "DNA_camera_types.h"
36 #include "DNA_lamp_types.h"
37 #include "DNA_scene_types.h"
38
39 #include "MEM_guardedalloc.h"
40
41 #include "BLI_math.h"
42 #include "BLI_blenlib.h"
43 #include "BLI_editVert.h"
44 #include "BLI_rand.h"
45
46 #include "BKE_anim.h"
47 #include "BKE_action.h"
48 #include "BKE_context.h"
49 #include "BKE_object.h"
50 #include "BKE_global.h"
51 #include "BKE_main.h"
52 #include "BKE_report.h"
53 #include "BKE_scene.h"
54 #include "BKE_screen.h"
55 #include "BKE_utildefines.h"
56 #include "BKE_depsgraph.h" /* for fly mode updating */
57
58
59 #include "BIF_gl.h"
60 #include "BIF_glutil.h"
61
62 #include "WM_api.h"
63 #include "WM_types.h"
64
65 #include "ED_keyframing.h"
66 #include "ED_screen.h"
67 #include "ED_armature.h"
68
69 #include "GPU_draw.h"
70
71
72 #include "PIL_time.h" /* smoothview */
73
74 #if GAMEBLENDER == 1
75 #include "SYS_System.h"
76 #endif
77
78 #include "view3d_intern.h"      // own include
79
80 /* use this call when executing an operator,
81    event system doesn't set for each event the
82    opengl drawing context */
83 void view3d_operator_needs_opengl(const bContext *C)
84 {
85         ARegion *ar= CTX_wm_region(C);
86
87         /* for debugging purpose, context should always be OK */
88         if(ar->regiontype!=RGN_TYPE_WINDOW)
89                 printf("view3d_operator_needs_opengl error, wrong region\n");
90         else {
91                 RegionView3D *rv3d= ar->regiondata;
92                 
93                 wmSubWindowSet(CTX_wm_window(C), ar->swinid);
94                 glMatrixMode(GL_PROJECTION);
95                 glLoadMatrixf(rv3d->winmat);
96                 glMatrixMode(GL_MODELVIEW);
97                 glLoadMatrixf(rv3d->viewmat);
98         }
99 }
100
101 float *give_cursor(Scene *scene, View3D *v3d)
102 {
103         if(v3d && v3d->localvd) return v3d->cursor;
104         else return scene->cursor;
105 }
106
107
108 /* Gets the lens and clipping values from a camera of lamp type object */
109 static void object_lens_clip_settings(Object *ob, float *lens, float *clipsta, float *clipend)
110 {       
111         if (!ob) return;
112         
113         if(ob->type==OB_LAMP ) {
114                 Lamp *la = ob->data;
115                 if (lens) {
116                         float x1, fac;
117                         fac= cos( M_PI*la->spotsize/360.0);
118                         x1= saacos(fac);
119                         *lens= 16.0*fac/sin(x1);
120                 }
121                 if (clipsta)    *clipsta= la->clipsta;
122                 if (clipend)    *clipend= la->clipend;
123         }
124         else if(ob->type==OB_CAMERA) {
125                 Camera *cam= ob->data;
126                 if (lens)               *lens= cam->lens;
127                 if (clipsta)    *clipsta= cam->clipsta;
128                 if (clipend)    *clipend= cam->clipend;
129         }
130         else {
131                 if (lens)               *lens= 35.0f;
132         }
133 }
134
135
136 /* Gets the view trasnformation from a camera
137 * currently dosnt take camzoom into account
138
139 * The dist is not modified for this function, if NULL its assimed zero
140 * */
141 void view3d_settings_from_ob(Object *ob, float *ofs, float *quat, float *dist, float *lens)
142 {
143         if (!ob) return;
144
145         /* Offset */
146         if (ofs)
147                 negate_v3_v3(ofs, ob->obmat[3]);
148
149         /* Quat */
150         if (quat) {
151                 float imat[4][4];
152                 invert_m4_m4(imat, ob->obmat);
153                 mat4_to_quat(quat, imat);
154         }
155
156         if (dist) {
157                 float vec[3] = {0.0f, 0.0f, -(*dist)};
158                 float tquat[4];
159
160                 mat4_to_quat(tquat, ob->obmat);
161
162                 mul_qt_v3(tquat, vec);
163
164                 sub_v3_v3(ofs, vec);
165         }
166
167         /* Lens */
168         if (lens)
169                 object_lens_clip_settings(ob, lens, NULL, NULL);
170 }
171
172
173 /* ****************** smooth view operator ****************** */
174 /* This operator is one of the 'timer refresh' ones like animation playback */
175
176 struct SmoothViewStore {
177         float orig_dist, new_dist;
178         float orig_lens, new_lens;
179         float orig_quat[4], new_quat[4];
180         float orig_ofs[3], new_ofs[3];
181         
182         int to_camera, orig_view;
183         
184         double time_allowed;
185 };
186
187 /* will start timer if appropriate */
188 /* the arguments are the desired situation */
189 void smooth_view(bContext *C, Object *oldcamera, Object *camera, float *ofs, float *quat, float *dist, float *lens)
190 {
191         View3D *v3d = CTX_wm_view3d(C);
192         RegionView3D *rv3d= CTX_wm_region_view3d(C);
193         struct SmoothViewStore sms;
194         
195         /* initialize sms */
196         memset(&sms,0,sizeof(struct SmoothViewStore));
197         VECCOPY(sms.new_ofs, rv3d->ofs);
198         QUATCOPY(sms.new_quat, rv3d->viewquat);
199         sms.new_dist= rv3d->dist;
200         sms.new_lens= v3d->lens;
201         sms.to_camera= 0;
202         
203         /* store the options we want to end with */
204         if(ofs) VECCOPY(sms.new_ofs, ofs);
205         if(quat) QUATCOPY(sms.new_quat, quat);
206         if(dist) sms.new_dist= *dist;
207         if(lens) sms.new_lens= *lens;
208         
209         if (camera) {
210                 view3d_settings_from_ob(camera, sms.new_ofs, sms.new_quat, &sms.new_dist, &sms.new_lens);
211                 sms.to_camera= 1; /* restore view3d values in end */
212         }
213         
214         if (C && U.smooth_viewtx) {
215                 int changed = 0; /* zero means no difference */
216                 
217                 if (sms.new_dist != rv3d->dist)
218                         changed = 1;
219                 if (sms.new_lens != v3d->lens)
220                         changed = 1;
221                 
222                 if ((sms.new_ofs[0]!=rv3d->ofs[0]) ||
223                         (sms.new_ofs[1]!=rv3d->ofs[1]) ||
224                         (sms.new_ofs[2]!=rv3d->ofs[2]) )
225                         changed = 1;
226                 
227                 if ((sms.new_quat[0]!=rv3d->viewquat[0]) ||
228                         (sms.new_quat[1]!=rv3d->viewquat[1]) ||
229                         (sms.new_quat[2]!=rv3d->viewquat[2]) ||
230                         (sms.new_quat[3]!=rv3d->viewquat[3]) )
231                         changed = 1;
232                 
233                 /* The new view is different from the old one
234                         * so animate the view */
235                 if (changed) {
236                         
237                         sms.time_allowed= (double)U.smooth_viewtx / 1000.0;
238                         
239                         /* if this is view rotation only
240                                 * we can decrease the time allowed by
241                                 * the angle between quats 
242                                 * this means small rotations wont lag */
243                         if (quat && !ofs && !dist) {
244                                  float vec1[3], vec2[3];
245                                 
246                                  VECCOPY(vec1, sms.new_quat);
247                                  VECCOPY(vec2, sms.orig_quat);
248                                  normalize_v3(vec1);
249                                  normalize_v3(vec2);
250                                  /* scale the time allowed by the rotation */
251                                  sms.time_allowed *= angle_normalized_v3v3(vec1, vec2)/(M_PI/2); 
252                         }
253                         
254                         /* original values */
255                         if (oldcamera) {
256                                 sms.orig_dist= rv3d->dist; // below function does weird stuff with it...
257                                 view3d_settings_from_ob(oldcamera, sms.orig_ofs, sms.orig_quat, &sms.orig_dist, &sms.orig_lens);
258                         }
259                         else {
260                                 VECCOPY(sms.orig_ofs, rv3d->ofs);
261                                 QUATCOPY(sms.orig_quat, rv3d->viewquat);
262                                 sms.orig_dist= rv3d->dist;
263                                 sms.orig_lens= v3d->lens;
264                         }
265                         /* grid draw as floor */
266                         if((rv3d->viewlock & RV3D_LOCKED)==0) {
267                                 /* use existing if exists, means multiple calls to smooth view wont loose the original 'view' setting */
268                                 sms.orig_view= rv3d->sms ? rv3d->sms->orig_view : rv3d->view;
269                                 rv3d->view= 0;
270                         }
271
272                         /* ensure it shows correct */
273                         if(sms.to_camera) rv3d->persp= RV3D_PERSP;
274
275                         rv3d->rflag |= RV3D_NAVIGATING;
276                         
277                         /* keep track of running timer! */
278                         if(rv3d->sms==NULL)
279                                 rv3d->sms= MEM_mallocN(sizeof(struct SmoothViewStore), "smoothview v3d");
280                         *rv3d->sms= sms;
281                         if(rv3d->smooth_timer)
282                                 WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), rv3d->smooth_timer);
283                         /* TIMER1 is hardcoded in keymap */
284                         rv3d->smooth_timer= WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER1, 1.0/100.0); /* max 30 frs/sec */
285                         
286                         return;
287                 }
288         }
289         
290         /* if we get here nothing happens */
291         if(sms.to_camera==0) {
292                 VECCOPY(rv3d->ofs, sms.new_ofs);
293                 QUATCOPY(rv3d->viewquat, sms.new_quat);
294                 rv3d->dist = sms.new_dist;
295                 v3d->lens = sms.new_lens;
296         }
297         ED_region_tag_redraw(CTX_wm_region(C));
298 }
299
300 /* only meant for timer usage */
301 static int view3d_smoothview_invoke(bContext *C, wmOperator *op, wmEvent *event)
302 {
303         View3D *v3d = CTX_wm_view3d(C);
304         RegionView3D *rv3d= CTX_wm_region_view3d(C);
305         struct SmoothViewStore *sms= rv3d->sms;
306         double step, step_inv;
307         
308         /* escape if not our timer */
309         if(rv3d->smooth_timer==NULL || rv3d->smooth_timer!=event->customdata)
310                 return OPERATOR_PASS_THROUGH;
311         
312         step =  (rv3d->smooth_timer->duration)/sms->time_allowed;
313         
314         /* end timer */
315         if(step >= 1.0f) {
316                 
317                 /* if we went to camera, store the original */
318                 if(sms->to_camera) {
319                         rv3d->persp= RV3D_CAMOB;
320                         VECCOPY(rv3d->ofs, sms->orig_ofs);
321                         QUATCOPY(rv3d->viewquat, sms->orig_quat);
322                         rv3d->dist = sms->orig_dist;
323                         v3d->lens = sms->orig_lens;
324                 }
325                 else {
326                         VECCOPY(rv3d->ofs, sms->new_ofs);
327                         QUATCOPY(rv3d->viewquat, sms->new_quat);
328                         rv3d->dist = sms->new_dist;
329                         v3d->lens = sms->new_lens;
330                 }
331                 
332                 if((rv3d->viewlock & RV3D_LOCKED)==0) {
333                         rv3d->view= sms->orig_view;
334                 }
335
336                 MEM_freeN(rv3d->sms);
337                 rv3d->sms= NULL;
338                 
339                 WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), rv3d->smooth_timer);
340                 rv3d->smooth_timer= NULL;
341                 rv3d->rflag &= ~RV3D_NAVIGATING;
342         }
343         else {
344                 int i;
345                 
346                 /* ease in/out */
347                 if (step < 0.5) step = (float)pow(step*2, 2)/2;
348                 else                    step = (float)1-(pow(2*(1-step),2)/2);
349
350                 step_inv = 1.0-step;
351
352                 for (i=0; i<3; i++)
353                         rv3d->ofs[i] = sms->new_ofs[i]*step + sms->orig_ofs[i]*step_inv;
354
355                 interp_qt_qtqt(rv3d->viewquat, sms->orig_quat, sms->new_quat, step);
356                 
357                 rv3d->dist = sms->new_dist*step + sms->orig_dist*step_inv;
358                 v3d->lens = sms->new_lens*step + sms->orig_lens*step_inv;
359         }
360         
361         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, v3d);
362         
363         return OPERATOR_FINISHED;
364 }
365
366 void VIEW3D_OT_smoothview(wmOperatorType *ot)
367 {
368         
369         /* identifiers */
370         ot->name= "Smooth View";
371         ot->idname= "VIEW3D_OT_smoothview";
372         ot->description="The time to animate the change of view (in milliseconds)";
373         
374         /* api callbacks */
375         ot->invoke= view3d_smoothview_invoke;
376         
377         ot->poll= ED_operator_view3d_active;
378 }
379
380 /* ****************** change view operators ****************** */
381
382 static void setcameratoview3d(View3D *v3d, RegionView3D *rv3d, Object *ob)
383 {
384         float dvec[3];
385         float mat3[3][3];
386
387         mul_v3_v3fl(dvec, rv3d->viewinv[2], rv3d->dist);
388         sub_v3_v3v3(ob->loc, dvec, rv3d->ofs);
389         rv3d->viewquat[0]= -rv3d->viewquat[0];
390
391         // quat_to_eul( ob->rot,rv3d->viewquat); // in 2.4x for xyz eulers only
392         quat_to_mat3(mat3, rv3d->viewquat);
393         object_mat3_to_rot(ob, mat3, 0);
394
395         rv3d->viewquat[0]= -rv3d->viewquat[0];
396         
397         ob->recalc= OB_RECALC_OB;
398 }
399
400
401 static int view3d_setcameratoview_exec(bContext *C, wmOperator *op)
402 {
403         View3D *v3d = CTX_wm_view3d(C);
404         RegionView3D *rv3d= CTX_wm_region_view3d(C);
405
406         setcameratoview3d(v3d, rv3d, v3d->camera);
407         rv3d->persp = RV3D_CAMOB;
408         
409         WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, v3d->camera);
410         
411         return OPERATOR_FINISHED;
412
413 }
414
415 int view3d_setcameratoview_poll(bContext *C)
416 {
417         View3D *v3d = CTX_wm_view3d(C);
418         RegionView3D *rv3d= CTX_wm_region_view3d(C);
419
420         if (v3d==NULL || v3d->camera==NULL)     return 0;
421         if (rv3d && rv3d->viewlock != 0)                return 0;
422         return 1;
423 }
424
425 void VIEW3D_OT_setcameratoview(wmOperatorType *ot)
426 {
427         
428         /* identifiers */
429         ot->name= "Align Camera To View";
430         ot->description= "Set camera view to active view";
431         ot->idname= "VIEW3D_OT_camera_to_view";
432         
433         /* api callbacks */
434         ot->exec= view3d_setcameratoview_exec;  
435         ot->poll= view3d_setcameratoview_poll;
436         
437         /* flags */
438         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
439 }
440
441
442 static int view3d_setobjectascamera_exec(bContext *C, wmOperator *op)
443 {
444         View3D *v3d = CTX_wm_view3d(C);
445         RegionView3D *rv3d= CTX_wm_region_view3d(C);
446         Scene *scene= CTX_data_scene(C);
447         
448         if(BASACT) {
449                 rv3d->persp= RV3D_CAMOB;
450                 v3d->camera= OBACT;
451                 if(v3d->scenelock)
452                         scene->camera= OBACT;
453                 smooth_view(C, NULL, v3d->camera, rv3d->ofs, rv3d->viewquat, &rv3d->dist, &v3d->lens);
454         }
455         
456         WM_event_add_notifier(C, NC_SCENE|ND_RENDER_OPTIONS|NC_OBJECT|ND_DRAW, CTX_data_scene(C));
457         
458         return OPERATOR_FINISHED;
459 }
460
461 void VIEW3D_OT_object_as_camera(wmOperatorType *ot)
462 {
463         
464         /* identifiers */
465         ot->name= "Set Active Object as Camera";
466         ot->description= "Set the active object as the active camera for this view or scene";
467         ot->idname= "VIEW3D_OT_object_as_camera";
468         
469         /* api callbacks */
470         ot->exec= view3d_setobjectascamera_exec;        
471         ot->poll= ED_operator_view3d_active;
472         
473         /* flags */
474         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
475 }
476
477 /* ********************************** */
478
479 void view3d_calculate_clipping(BoundBox *bb, float planes[4][4], bglMats *mats, rcti *rect)
480 {
481         double xs, ys, p[3];
482         short val;
483
484         /* near zero floating point values can give issues with gluUnProject
485                 in side view on some implementations */
486         if(fabs(mats->modelview[0]) < 1e-6) mats->modelview[0]= 0.0;
487         if(fabs(mats->modelview[5]) < 1e-6) mats->modelview[5]= 0.0;
488
489         /* Set up viewport so that gluUnProject will give correct values */
490         mats->viewport[0] = 0;
491         mats->viewport[1] = 0;
492
493         /* four clipping planes and bounding volume */
494         /* first do the bounding volume */
495         for(val=0; val<4; val++) {
496                 xs= (val==0||val==3)?rect->xmin:rect->xmax;
497                 ys= (val==0||val==1)?rect->ymin:rect->ymax;
498
499                 gluUnProject(xs, ys, 0.0, mats->modelview, mats->projection, mats->viewport, &p[0], &p[1], &p[2]);
500                 VECCOPY(bb->vec[val], p);
501
502                 gluUnProject(xs, ys, 1.0, mats->modelview, mats->projection, mats->viewport, &p[0], &p[1], &p[2]);
503                 VECCOPY(bb->vec[4+val], p);
504         }
505
506         /* then plane equations */
507         for(val=0; val<4; val++) {
508
509                 normal_tri_v3(planes[val], bb->vec[val], bb->vec[val==3?0:val+1], bb->vec[val+4]);
510
511                 planes[val][3]= - planes[val][0]*bb->vec[val][0]
512                         - planes[val][1]*bb->vec[val][1]
513                         - planes[val][2]*bb->vec[val][2];
514         }
515 }
516
517 /* create intersection coordinates in view Z direction at mouse coordinates */
518 void viewline(ARegion *ar, View3D *v3d, float mval[2], float ray_start[3], float ray_end[3])
519 {
520         RegionView3D *rv3d= ar->regiondata;
521         float vec[4];
522         int a;
523         
524         if(!get_view3d_ortho(v3d, rv3d)) {
525                 vec[0]= 2.0f * mval[0] / ar->winx - 1;
526                 vec[1]= 2.0f * mval[1] / ar->winy - 1;
527                 vec[2]= -1.0f;
528                 vec[3]= 1.0f;
529                 
530                 mul_m4_v4(rv3d->persinv, vec);
531                 mul_v3_fl(vec, 1.0f / vec[3]);
532                 
533                 copy_v3_v3(ray_start, rv3d->viewinv[3]);
534                 sub_v3_v3(vec, ray_start);
535                 normalize_v3(vec);
536                 
537                 VECADDFAC(ray_start, rv3d->viewinv[3], vec, v3d->near);
538                 VECADDFAC(ray_end, rv3d->viewinv[3], vec, v3d->far);
539         }
540         else {
541                 vec[0] = 2.0f * mval[0] / ar->winx - 1;
542                 vec[1] = 2.0f * mval[1] / ar->winy - 1;
543                 vec[2] = 0.0f;
544                 vec[3] = 1.0f;
545                 
546                 mul_m4_v4(rv3d->persinv, vec);
547                 
548                 VECADDFAC(ray_start, vec, rv3d->viewinv[2],  1000.0f);
549                 VECADDFAC(ray_end, vec, rv3d->viewinv[2], -1000.0f);
550         }
551
552         /* clipping */
553         if(rv3d->rflag & RV3D_CLIPPING)
554                 for(a=0; a<4; a++)
555                         clip_line_plane(ray_start, ray_end, rv3d->clip[a]);
556 }
557
558 /* create intersection ray in view Z direction at mouse coordinates */
559 void viewray(ARegion *ar, View3D *v3d, float mval[2], float ray_start[3], float ray_normal[3])
560 {
561         float ray_end[3];
562         
563         viewline(ar, v3d, mval, ray_start, ray_end);
564         sub_v3_v3v3(ray_normal, ray_end, ray_start);
565         normalize_v3(ray_normal);
566 }
567
568 void viewvector(RegionView3D *rv3d, float coord[3], float vec[3])
569 {
570         if (rv3d->persp != RV3D_ORTHO)
571         {
572                 float p1[4], p2[4];
573
574                 VECCOPY(p1, coord);
575                 p1[3] = 1.0f;
576                 VECCOPY(p2, p1);
577                 p2[3] = 1.0f;
578                 mul_m4_v4(rv3d->viewmat, p2);
579
580                 mul_v3_fl(p2, 2.0f);
581
582                 mul_m4_v4(rv3d->viewinv, p2);
583
584                 sub_v3_v3v3(vec, p1, p2);
585         }
586         else {
587                 VECCOPY(vec, rv3d->viewinv[2]);
588         }
589         normalize_v3(vec);
590 }
591
592 void initgrabz(RegionView3D *rv3d, float x, float y, float z)
593 {
594         if(rv3d==NULL) return;
595         rv3d->zfac= rv3d->persmat[0][3]*x+ rv3d->persmat[1][3]*y+ rv3d->persmat[2][3]*z+ rv3d->persmat[3][3];
596         
597         /* if x,y,z is exactly the viewport offset, zfac is 0 and we don't want that 
598                 * (accounting for near zero values)
599                 * */
600         if (rv3d->zfac < 1.e-6f && rv3d->zfac > -1.e-6f) rv3d->zfac = 1.0f;
601         
602         /* Negative zfac means x, y, z was behind the camera (in perspective).
603                 * This gives flipped directions, so revert back to ok default case.
604         */
605         // NOTE: I've changed this to flip zfac to be positive again for now so that GPencil draws ok
606         //      -- Aligorith, 2009Aug31
607         //if (rv3d->zfac < 0.0f) rv3d->zfac = 1.0f;
608         if (rv3d->zfac < 0.0f) rv3d->zfac= -rv3d->zfac;
609 }
610
611 /* always call initgrabz */
612 void window_to_3d(ARegion *ar, float *vec, short mx, short my)
613 {
614         RegionView3D *rv3d= ar->regiondata;
615         
616         float dx= ((float)(mx-(ar->winx/2)))*rv3d->zfac/(ar->winx/2);
617         float dy= ((float)(my-(ar->winy/2)))*rv3d->zfac/(ar->winy/2);
618         
619         float fz= rv3d->persmat[0][3]*vec[0]+ rv3d->persmat[1][3]*vec[1]+ rv3d->persmat[2][3]*vec[2]+ rv3d->persmat[3][3];
620         fz= fz/rv3d->zfac;
621         
622         vec[0]= (rv3d->persinv[0][0]*dx + rv3d->persinv[1][0]*dy+ rv3d->persinv[2][0]*fz)-rv3d->ofs[0];
623         vec[1]= (rv3d->persinv[0][1]*dx + rv3d->persinv[1][1]*dy+ rv3d->persinv[2][1]*fz)-rv3d->ofs[1];
624         vec[2]= (rv3d->persinv[0][2]*dx + rv3d->persinv[1][2]*dy+ rv3d->persinv[2][2]*fz)-rv3d->ofs[2];
625         
626 }
627
628 /* always call initgrabz */
629 /* only to detect delta motion */
630 void window_to_3d_delta(ARegion *ar, float *vec, short mx, short my)
631 {
632         RegionView3D *rv3d= ar->regiondata;
633         float dx, dy;
634         
635         dx= 2.0f*mx*rv3d->zfac/ar->winx;
636         dy= 2.0f*my*rv3d->zfac/ar->winy;
637         
638         vec[0]= (rv3d->persinv[0][0]*dx + rv3d->persinv[1][0]*dy);
639         vec[1]= (rv3d->persinv[0][1]*dx + rv3d->persinv[1][1]*dy);
640         vec[2]= (rv3d->persinv[0][2]*dx + rv3d->persinv[1][2]*dy);
641 }
642
643 float read_cached_depth(ViewContext *vc, int x, int y)
644 {
645         ViewDepths *vd = vc->rv3d->depths;
646                 
647         x -= vc->ar->winrct.xmin;
648         y -= vc->ar->winrct.ymin;
649
650         if(vd && vd->depths && x > 0 && y > 0 && x < vd->w && y < vd->h)
651                 return vd->depths[y * vd->w + x];
652         else
653                 return 1;
654 }
655
656 void request_depth_update(RegionView3D *rv3d)
657 {
658         if(rv3d->depths)
659                 rv3d->depths->damaged= 1;
660 }
661
662 void view3d_get_object_project_mat(RegionView3D *rv3d, Object *ob, float pmat[4][4])
663 {
664         float vmat[4][4];
665         
666         mul_m4_m4m4(vmat, ob->obmat, rv3d->viewmat);
667         mul_m4_m4m4(pmat, vmat, rv3d->winmat);
668 }
669
670 /* Uses window coordinates (x,y) and depth component z to find a point in
671    modelspace */
672 void view3d_unproject(bglMats *mats, float out[3], const short x, const short y, const float z)
673 {
674         double ux, uy, uz;
675
676                 gluUnProject(x,y,z, mats->modelview, mats->projection,
677                          (GLint *)mats->viewport, &ux, &uy, &uz );
678         out[0] = ux;
679         out[1] = uy;
680         out[2] = uz;
681 }
682
683 /* use above call to get projecting mat */
684 void view3d_project_float(ARegion *ar, float *vec, float *adr, float mat[4][4])
685 {
686         float vec4[4];
687         
688         adr[0]= IS_CLIPPED;
689         VECCOPY(vec4, vec);
690         vec4[3]= 1.0;
691         
692         mul_m4_v4(mat, vec4);
693         
694         if( vec4[3]>FLT_EPSILON ) {
695                 adr[0] = (float)(ar->winx/2.0f)+(ar->winx/2.0f)*vec4[0]/vec4[3];        
696                 adr[1] = (float)(ar->winy/2.0f)+(ar->winy/2.0f)*vec4[1]/vec4[3];
697         } else {
698                 adr[0] = adr[1] = 0.0f;
699         }
700 }
701
702 int boundbox_clip(RegionView3D *rv3d, float obmat[][4], BoundBox *bb)
703 {
704         /* return 1: draw */
705         
706         float mat[4][4];
707         float vec[4], min, max;
708         int a, flag= -1, fl;
709         
710         if(bb==NULL) return 1;
711         if(bb->flag & OB_BB_DISABLED) return 1;
712         
713         mul_m4_m4m4(mat, obmat, rv3d->persmat);
714         
715         for(a=0; a<8; a++) {
716                 VECCOPY(vec, bb->vec[a]);
717                 vec[3]= 1.0;
718                 mul_m4_v4(mat, vec);
719                 max= vec[3];
720                 min= -vec[3];
721                 
722                 fl= 0;
723                 if(vec[0] < min) fl+= 1;
724                 if(vec[0] > max) fl+= 2;
725                 if(vec[1] < min) fl+= 4;
726                 if(vec[1] > max) fl+= 8;
727                 if(vec[2] < min) fl+= 16;
728                 if(vec[2] > max) fl+= 32;
729                 
730                 flag &= fl;
731                 if(flag==0) return 1;
732         }
733         
734         return 0;
735 }
736
737 void project_short(ARegion *ar, float *vec, short *adr) /* clips */
738 {
739         RegionView3D *rv3d= ar->regiondata;
740         float fx, fy, vec4[4];
741         
742         adr[0]= IS_CLIPPED;
743         
744         if(rv3d->rflag & RV3D_CLIPPING) {
745                 if(view3d_test_clipping(rv3d, vec, 0))
746                         return;
747         }
748         
749         VECCOPY(vec4, vec);
750         vec4[3]= 1.0;
751         mul_m4_v4(rv3d->persmat, vec4);
752         
753         if( vec4[3]>BL_NEAR_CLIP ) {    /* 0.001 is the NEAR clipping cutoff for picking */
754                 fx= (ar->winx/2)*(1 + vec4[0]/vec4[3]);
755                 
756                 if( fx>0 && fx<ar->winx) {
757                         
758                         fy= (ar->winy/2)*(1 + vec4[1]/vec4[3]);
759                         
760                         if(fy>0.0 && fy< (float)ar->winy) {
761                                 adr[0]= (short)floor(fx); 
762                                 adr[1]= (short)floor(fy);
763                         }
764                 }
765         }
766 }
767
768 void project_int(ARegion *ar, float *vec, int *adr)
769 {
770         RegionView3D *rv3d= ar->regiondata;
771         float fx, fy, vec4[4];
772         
773         adr[0]= (int)2140000000.0f;
774         VECCOPY(vec4, vec);
775         vec4[3]= 1.0;
776         
777         mul_m4_v4(rv3d->persmat, vec4);
778         
779         if( vec4[3]>BL_NEAR_CLIP ) {    /* 0.001 is the NEAR clipping cutoff for picking */
780                 fx= (ar->winx/2)*(1 + vec4[0]/vec4[3]);
781                 
782                 if( fx>-2140000000.0f && fx<2140000000.0f) {
783                         fy= (ar->winy/2)*(1 + vec4[1]/vec4[3]);
784                         
785                         if(fy>-2140000000.0f && fy<2140000000.0f) {
786                                 adr[0]= (int)floor(fx); 
787                                 adr[1]= (int)floor(fy);
788                         }
789                 }
790         }
791 }
792
793 void project_int_noclip(ARegion *ar, float *vec, int *adr)
794 {
795         RegionView3D *rv3d= ar->regiondata;
796         float fx, fy, vec4[4];
797         
798         VECCOPY(vec4, vec);
799         vec4[3]= 1.0;
800         
801         mul_m4_v4(rv3d->persmat, vec4);
802         
803         if( fabs(vec4[3]) > BL_NEAR_CLIP ) {
804                 fx = (ar->winx/2)*(1 + vec4[0]/vec4[3]);
805                 fy = (ar->winy/2)*(1 + vec4[1]/vec4[3]);
806                 
807                 adr[0] = (int)floor(fx); 
808                 adr[1] = (int)floor(fy);
809         }
810         else
811         {
812                 adr[0] = ar->winx / 2;
813                 adr[1] = ar->winy / 2;
814         }
815 }
816
817 void project_short_noclip(ARegion *ar, float *vec, short *adr)
818 {
819         RegionView3D *rv3d= ar->regiondata;
820         float fx, fy, vec4[4];
821         
822         adr[0]= IS_CLIPPED;
823         VECCOPY(vec4, vec);
824         vec4[3]= 1.0;
825         
826         mul_m4_v4(rv3d->persmat, vec4);
827         
828         if( vec4[3]>BL_NEAR_CLIP ) {    /* 0.001 is the NEAR clipping cutoff for picking */
829                 fx= (ar->winx/2)*(1 + vec4[0]/vec4[3]);
830                 
831                 if( fx>-32700 && fx<32700) {
832                         
833                         fy= (ar->winy/2)*(1 + vec4[1]/vec4[3]);
834                         
835                         if(fy>-32700.0 && fy<32700.0) {
836                                 adr[0]= (short)floor(fx); 
837                                 adr[1]= (short)floor(fy);
838                         }
839                 }
840         }
841 }
842
843 void project_float(ARegion *ar, float *vec, float *adr)
844 {
845         RegionView3D *rv3d= ar->regiondata;
846         float vec4[4];
847         
848         adr[0]= IS_CLIPPED;
849         VECCOPY(vec4, vec);
850         vec4[3]= 1.0;
851         
852         mul_m4_v4(rv3d->persmat, vec4);
853         
854         if( vec4[3]>BL_NEAR_CLIP ) {
855                 adr[0] = (float)(ar->winx/2.0)+(ar->winx/2.0)*vec4[0]/vec4[3];  
856                 adr[1] = (float)(ar->winy/2.0)+(ar->winy/2.0)*vec4[1]/vec4[3];
857         }
858 }
859
860 void project_float_noclip(ARegion *ar, float *vec, float *adr)
861 {
862         RegionView3D *rv3d= ar->regiondata;
863         float vec4[4];
864         
865         VECCOPY(vec4, vec);
866         vec4[3]= 1.0;
867         
868         mul_m4_v4(rv3d->persmat, vec4);
869         
870         if( fabs(vec4[3]) > BL_NEAR_CLIP ) {
871                 adr[0] = (float)(ar->winx/2.0)+(ar->winx/2.0)*vec4[0]/vec4[3];  
872                 adr[1] = (float)(ar->winy/2.0)+(ar->winy/2.0)*vec4[1]/vec4[3];
873         }
874         else
875         {
876                 adr[0] = ar->winx / 2.0f;
877                 adr[1] = ar->winy / 2.0f;
878         }
879 }
880
881 int get_view3d_ortho(View3D *v3d, RegionView3D *rv3d)
882 {
883   Camera *cam;
884   
885   if(rv3d->persp==RV3D_CAMOB) {
886           if(v3d->camera && v3d->camera->type==OB_CAMERA) {
887                   cam= v3d->camera->data;
888
889                   if(cam && cam->type==CAM_ORTHO)
890                           return 1;
891                   else
892                           return 0;
893           }
894           else
895                   return 0;
896   }
897   
898   if(rv3d->persp==RV3D_ORTHO)
899           return 1;
900
901   return 0;
902 }
903
904 /* copies logic of get_view3d_viewplane(), keep in sync */
905 int get_view3d_cliprange(View3D *v3d, RegionView3D *rv3d, float *clipsta, float *clipend)
906 {
907         int orth= 0;
908
909         *clipsta= v3d->near;
910         *clipend= v3d->far;
911
912         if(rv3d->persp==RV3D_CAMOB) {
913                 if(v3d->camera) {
914                         if(v3d->camera->type==OB_LAMP ) {
915                                 Lamp *la= v3d->camera->data;
916                                 *clipsta= la->clipsta;
917                                 *clipend= la->clipend;
918                         }
919                         else if(v3d->camera->type==OB_CAMERA) {
920                                 Camera *cam= v3d->camera->data;
921                                 *clipsta= cam->clipsta;
922                                 *clipend= cam->clipend;
923
924                                 if(cam->type==CAM_ORTHO)
925                                         orth= 1;
926                         }
927                 }
928         }
929
930         if(rv3d->persp==RV3D_ORTHO) {
931                 *clipend *= 0.5;        // otherwise too extreme low zbuffer quality
932                 *clipsta= - *clipend;
933                 orth= 1;
934         }
935
936         return orth;
937 }
938
939 /* also exposed in previewrender.c */
940 int get_view3d_viewplane(View3D *v3d, RegionView3D *rv3d, int winxi, int winyi, rctf *viewplane, float *clipsta, float *clipend, float *pixsize)
941 {
942         Camera *cam=NULL;
943         float lens, fac, x1, y1, x2, y2;
944         float winx= (float)winxi, winy= (float)winyi;
945         int orth= 0;
946         
947         lens= v3d->lens;        
948         
949         *clipsta= v3d->near;
950         *clipend= v3d->far;
951         
952         if(rv3d->persp==RV3D_CAMOB) {
953                 if(v3d->camera) {
954                         if(v3d->camera->type==OB_LAMP ) {
955                                 Lamp *la;
956                                 
957                                 la= v3d->camera->data;
958                                 fac= cos( M_PI*la->spotsize/360.0);
959                                 
960                                 x1= saacos(fac);
961                                 lens= 16.0*fac/sin(x1);
962                                 
963                                 *clipsta= la->clipsta;
964                                 *clipend= la->clipend;
965                         }
966                         else if(v3d->camera->type==OB_CAMERA) {
967                                 cam= v3d->camera->data;
968                                 lens= cam->lens;
969                                 *clipsta= cam->clipsta;
970                                 *clipend= cam->clipend;
971                         }
972                 }
973         }
974         
975         if(rv3d->persp==RV3D_ORTHO) {
976                 if(winx>winy) x1= -rv3d->dist;
977                 else x1= -winx*rv3d->dist/winy;
978                 x2= -x1;
979                 
980                 if(winx>winy) y1= -winy*rv3d->dist/winx;
981                 else y1= -rv3d->dist;
982                 y2= -y1;
983                 
984                 *clipend *= 0.5;        // otherwise too extreme low zbuffer quality
985                 *clipsta= - *clipend;
986                 orth= 1;
987         }
988         else {
989                 /* fac for zoom, also used for camdx */
990                 if(rv3d->persp==RV3D_CAMOB) {
991                         fac= (1.41421+( (float)rv3d->camzoom )/50.0);
992                         fac*= fac;
993                 }
994                 else fac= 2.0;
995                 
996                 /* viewplane size depends... */
997                 if(cam && cam->type==CAM_ORTHO) {
998                         /* ortho_scale == 1 means exact 1 to 1 mapping */
999                         float dfac= 2.0*cam->ortho_scale/fac;
1000                         
1001                         if(winx>winy) x1= -dfac;
1002                         else x1= -winx*dfac/winy;
1003                         x2= -x1;
1004                         
1005                         if(winx>winy) y1= -winy*dfac/winx;
1006                         else y1= -dfac;
1007                         y2= -y1;
1008                         orth= 1;
1009                 }
1010                 else {
1011                         float dfac;
1012                         
1013                         if(winx>winy) dfac= 64.0/(fac*winx*lens);
1014                         else dfac= 64.0/(fac*winy*lens);
1015                         
1016                         x1= - *clipsta * winx*dfac;
1017                         x2= -x1;
1018                         y1= - *clipsta * winy*dfac;
1019                         y2= -y1;
1020                         orth= 0;
1021                 }
1022                 /* cam view offset */
1023                 if(cam) {
1024                         float dx= 0.5*fac*rv3d->camdx*(x2-x1);
1025                         float dy= 0.5*fac*rv3d->camdy*(y2-y1);
1026                         x1+= dx;
1027                         x2+= dx;
1028                         y1+= dy;
1029                         y2+= dy;
1030                 }
1031         }
1032         
1033         if(pixsize) {
1034                 float viewfac;
1035                 
1036                 if(orth) {
1037                         viewfac= (winx >= winy)? winx: winy;
1038                         *pixsize= 1.0f/viewfac;
1039                 }
1040                 else {
1041                         viewfac= (((winx >= winy)? winx: winy)*lens)/32.0;
1042                         *pixsize= *clipsta/viewfac;
1043                 }
1044         }
1045         
1046         viewplane->xmin= x1;
1047         viewplane->ymin= y1;
1048         viewplane->xmax= x2;
1049         viewplane->ymax= y2;
1050         
1051         return orth;
1052 }
1053
1054 void setwinmatrixview3d(ARegion *ar, View3D *v3d, rctf *rect)           /* rect: for picking */
1055 {
1056         RegionView3D *rv3d= ar->regiondata;
1057         rctf viewplane;
1058         float clipsta, clipend, x1, y1, x2, y2;
1059         int orth;
1060         
1061         orth= get_view3d_viewplane(v3d, rv3d, ar->winx, ar->winy, &viewplane, &clipsta, &clipend, NULL);
1062         //      printf("%d %d %f %f %f %f %f %f\n", winx, winy, viewplane.xmin, viewplane.ymin, viewplane.xmax, viewplane.ymax, clipsta, clipend);
1063         x1= viewplane.xmin;
1064         y1= viewplane.ymin;
1065         x2= viewplane.xmax;
1066         y2= viewplane.ymax;
1067         
1068         if(rect) {              /* picking */
1069                 rect->xmin/= (float)ar->winx;
1070                 rect->xmin= x1+rect->xmin*(x2-x1);
1071                 rect->ymin/= (float)ar->winy;
1072                 rect->ymin= y1+rect->ymin*(y2-y1);
1073                 rect->xmax/= (float)ar->winx;
1074                 rect->xmax= x1+rect->xmax*(x2-x1);
1075                 rect->ymax/= (float)ar->winy;
1076                 rect->ymax= y1+rect->ymax*(y2-y1);
1077                 
1078                 if(orth) wmOrtho(rect->xmin, rect->xmax, rect->ymin, rect->ymax, -clipend, clipend);
1079                 else wmFrustum(rect->xmin, rect->xmax, rect->ymin, rect->ymax, clipsta, clipend);
1080                 
1081         }
1082         else {
1083                 if(orth) wmOrtho(x1, x2, y1, y2, clipsta, clipend);
1084                 else wmFrustum(x1, x2, y1, y2, clipsta, clipend);
1085         }
1086
1087         /* update matrix in 3d view region */
1088         glGetFloatv(GL_PROJECTION_MATRIX, (float*)rv3d->winmat);
1089 }
1090
1091 static void obmat_to_viewmat(View3D *v3d, RegionView3D *rv3d, Object *ob, short smooth)
1092 {
1093         float bmat[4][4];
1094         float tmat[3][3];
1095         
1096         rv3d->view= 0; /* dont show the grid */
1097         
1098         copy_m4_m4(bmat, ob->obmat);
1099         normalize_m4(bmat);
1100         invert_m4_m4(rv3d->viewmat, bmat);
1101         
1102         /* view quat calculation, needed for add object */
1103         copy_m3_m4(tmat, rv3d->viewmat);
1104         if (smooth) {
1105                 float new_quat[4];
1106                 if (rv3d->persp==RV3D_CAMOB && v3d->camera) {
1107                         /* were from a camera view */
1108                         
1109                         float orig_ofs[3];
1110                         float orig_dist= rv3d->dist;
1111                         float orig_lens= v3d->lens;
1112                         VECCOPY(orig_ofs, rv3d->ofs);
1113                         
1114                         /* Switch from camera view */
1115                         mat3_to_quat( new_quat,tmat);
1116                         
1117                         rv3d->persp=RV3D_PERSP;
1118                         rv3d->dist= 0.0;
1119                         
1120                         view3d_settings_from_ob(v3d->camera, rv3d->ofs, NULL, NULL, &v3d->lens);
1121                         smooth_view(NULL, NULL, NULL, orig_ofs, new_quat, &orig_dist, &orig_lens); // XXX
1122                         
1123                         rv3d->persp=RV3D_CAMOB; /* just to be polite, not needed */
1124                         
1125                 } else {
1126                         mat3_to_quat( new_quat,tmat);
1127                         smooth_view(NULL, NULL, NULL, NULL, new_quat, NULL, NULL); // XXX
1128                 }
1129         } else {
1130                 mat3_to_quat( rv3d->viewquat,tmat);
1131         }
1132 }
1133
1134 #define QUATSET(a, b, c, d, e)  a[0]=b; a[1]=c; a[2]=d; a[3]=e; 
1135
1136 static void view3d_viewlock(RegionView3D *rv3d)
1137 {
1138         switch(rv3d->view) {
1139         case RV3D_VIEW_BOTTOM :
1140                 QUATSET(rv3d->viewquat,0.0, -1.0, 0.0, 0.0);
1141                 break;
1142                 
1143         case RV3D_VIEW_BACK:
1144                 QUATSET(rv3d->viewquat,0.0, 0.0, (float)-cos(M_PI/4.0), (float)-cos(M_PI/4.0));
1145                 break;
1146                 
1147         case RV3D_VIEW_LEFT:
1148                 QUATSET(rv3d->viewquat,0.5, -0.5, 0.5, 0.5);
1149                 break;
1150                 
1151         case RV3D_VIEW_TOP:
1152                 QUATSET(rv3d->viewquat,1.0, 0.0, 0.0, 0.0);
1153                 break;
1154                 
1155         case RV3D_VIEW_FRONT:
1156                 QUATSET(rv3d->viewquat,(float)cos(M_PI/4.0), (float)-sin(M_PI/4.0), 0.0, 0.0);
1157                 break;
1158                 
1159         case RV3D_VIEW_RIGHT:
1160                 QUATSET(rv3d->viewquat, 0.5, -0.5, -0.5, -0.5);
1161                 break;
1162         }
1163 }
1164
1165 /* give a 4x4 matrix from a perspective view, only needs viewquat, ofs and dist
1166  * basically the same as...
1167  *     rv3d->persp= RV3D_PERSP
1168  *     setviewmatrixview3d(scene, v3d, rv3d);
1169  *     setcameratoview3d(v3d, rv3d, v3d->camera);
1170  * ...but less of a hassle
1171  * */
1172 static void view3d_persp_mat4(RegionView3D *rv3d, float mat[][4])
1173 {
1174         float qt[4], dvec[3];
1175         copy_qt_qt(qt, rv3d->viewquat);
1176         qt[0]= -qt[0];
1177         quat_to_mat4(mat, qt);
1178         mat[3][2] -= rv3d->dist;
1179         translate_m4(mat, rv3d->ofs[0], rv3d->ofs[1], rv3d->ofs[2]);
1180         mul_v3_v3fl(dvec, mat[2], -rv3d->dist);
1181         sub_v3_v3v3(mat[3], dvec, rv3d->ofs);
1182 }
1183
1184 /* dont set windows active in in here, is used by renderwin too */
1185 void setviewmatrixview3d(Scene *scene, View3D *v3d, RegionView3D *rv3d)
1186 {
1187         if(rv3d->persp==RV3D_CAMOB) {       /* obs/camera */
1188                 if(v3d->camera) {
1189                         where_is_object(scene, v3d->camera);    
1190                         obmat_to_viewmat(v3d, rv3d, v3d->camera, 0);
1191                 }
1192                 else {
1193                         quat_to_mat4( rv3d->viewmat,rv3d->viewquat);
1194                         rv3d->viewmat[3][2]-= rv3d->dist;
1195                 }
1196         }
1197         else {
1198                 /* should be moved to better initialize later on XXX */
1199                 if(rv3d->viewlock)
1200                         view3d_viewlock(rv3d);
1201                 
1202                 quat_to_mat4( rv3d->viewmat,rv3d->viewquat);
1203                 if(rv3d->persp==RV3D_PERSP) rv3d->viewmat[3][2]-= rv3d->dist;
1204                 if(v3d->ob_centre) {
1205                         Object *ob= v3d->ob_centre;
1206                         float vec[3];
1207                         
1208                         VECCOPY(vec, ob->obmat[3]);
1209                         if(ob->type==OB_ARMATURE && v3d->ob_centre_bone[0]) {
1210                                 bPoseChannel *pchan= get_pose_channel(ob->pose, v3d->ob_centre_bone);
1211                                 if(pchan) {
1212                                         VECCOPY(vec, pchan->pose_mat[3]);
1213                                         mul_m4_v3(ob->obmat, vec);
1214                                 }
1215                         }
1216                         translate_m4( rv3d->viewmat,-vec[0], -vec[1], -vec[2]);
1217                 }
1218                 else translate_m4( rv3d->viewmat,rv3d->ofs[0], rv3d->ofs[1], rv3d->ofs[2]);
1219         }
1220 }
1221
1222 /* IGLuint-> GLuint*/
1223 /* Warning: be sure to account for a negative return value
1224 *   This is an error, "Too many objects in select buffer"
1225 *   and no action should be taken (can crash blender) if this happens
1226 */
1227 short view3d_opengl_select(ViewContext *vc, unsigned int *buffer, unsigned int bufsize, rcti *input)
1228 {
1229         Scene *scene= vc->scene;
1230         View3D *v3d= vc->v3d;
1231         ARegion *ar= vc->ar;
1232         rctf rect;
1233         short code, hits;
1234         char dt, dtx;
1235         
1236         G.f |= G_PICKSEL;
1237         
1238         /* case not a border select */
1239         if(input->xmin==input->xmax) {
1240                 rect.xmin= input->xmin-12;      // seems to be default value for bones only now
1241                 rect.xmax= input->xmin+12;
1242                 rect.ymin= input->ymin-12;
1243                 rect.ymax= input->ymin+12;
1244         }
1245         else {
1246                 rect.xmin= input->xmin;
1247                 rect.xmax= input->xmax;
1248                 rect.ymin= input->ymin;
1249                 rect.ymax= input->ymax;
1250         }
1251         
1252         setwinmatrixview3d(ar, v3d, &rect);
1253         mul_m4_m4m4(vc->rv3d->persmat, vc->rv3d->viewmat, vc->rv3d->winmat);
1254         
1255         if(v3d->drawtype > OB_WIRE) {
1256                 v3d->zbuf= TRUE;
1257                 glEnable(GL_DEPTH_TEST);
1258         }
1259         
1260         if(vc->rv3d->rflag & RV3D_CLIPPING)
1261                 view3d_set_clipping(vc->rv3d);
1262         
1263         glSelectBuffer( bufsize, (GLuint *)buffer);
1264         glRenderMode(GL_SELECT);
1265         glInitNames();  /* these two calls whatfor? It doesnt work otherwise */
1266         glPushName(-1);
1267         code= 1;
1268         
1269         if(vc->obedit && vc->obedit->type==OB_MBALL) {
1270                 draw_object(scene, ar, v3d, BASACT, DRAW_PICKING|DRAW_CONSTCOLOR);
1271         }
1272         else if((vc->obedit && vc->obedit->type==OB_ARMATURE)) {
1273                 /* if not drawing sketch, draw bones */
1274                 if(!BDR_drawSketchNames(vc)) {
1275                         draw_object(scene, ar, v3d, BASACT, DRAW_PICKING|DRAW_CONSTCOLOR);
1276                 }
1277         }
1278         else {
1279                 Base *base;
1280                 
1281                 v3d->xray= TRUE;        // otherwise it postpones drawing
1282                 for(base= scene->base.first; base; base= base->next) {
1283                         if(base->lay & v3d->lay) {
1284                                 
1285                                 if (base->object->restrictflag & OB_RESTRICT_SELECT)
1286                                         base->selcol= 0;
1287                                 else {
1288                                         base->selcol= code;
1289                                         glLoadName(code);
1290                                         draw_object(scene, ar, v3d, base, DRAW_PICKING|DRAW_CONSTCOLOR);
1291                                         
1292                                         /* we draw group-duplicators for selection too */
1293                                         if((base->object->transflag & OB_DUPLI) && base->object->dup_group) {
1294                                                 ListBase *lb;
1295                                                 DupliObject *dob;
1296                                                 Base tbase;
1297                                                 
1298                                                 tbase.flag= OB_FROMDUPLI;
1299                                                 lb= object_duplilist(scene, base->object);
1300                                                 
1301                                                 for(dob= lb->first; dob; dob= dob->next) {
1302                                                         tbase.object= dob->ob;
1303                                                         copy_m4_m4(dob->ob->obmat, dob->mat);
1304                                                         
1305                                                         /* extra service: draw the duplicator in drawtype of parent */
1306                                                         /* MIN2 for the drawtype to allow bounding box objects in groups for lods */
1307                                                         dt= tbase.object->dt;   tbase.object->dt= MIN2(tbase.object->dt, base->object->dt);
1308                                                         dtx= tbase.object->dtx; tbase.object->dtx= base->object->dtx;
1309
1310                                                         draw_object(scene, ar, v3d, &tbase, DRAW_PICKING|DRAW_CONSTCOLOR);
1311                                                         
1312                                                         tbase.object->dt= dt;
1313                                                         tbase.object->dtx= dtx;
1314
1315                                                         copy_m4_m4(dob->ob->obmat, dob->omat);
1316                                                 }
1317                                                 free_object_duplilist(lb);
1318                                         }
1319                                         code++;
1320                                 }                               
1321                         }
1322                 }
1323                 v3d->xray= FALSE;       // restore
1324         }
1325         
1326         glPopName();    /* see above (pushname) */
1327         hits= glRenderMode(GL_RENDER);
1328         
1329         G.f &= ~G_PICKSEL;
1330         setwinmatrixview3d(ar, v3d, NULL);
1331         mul_m4_m4m4(vc->rv3d->persmat, vc->rv3d->viewmat, vc->rv3d->winmat);
1332         
1333         if(v3d->drawtype > OB_WIRE) {
1334                 v3d->zbuf= 0;
1335                 glDisable(GL_DEPTH_TEST);
1336         }
1337 // XXX  persp(PERSP_WIN);
1338         
1339         if(vc->rv3d->rflag & RV3D_CLIPPING)
1340                 view3d_clr_clipping();
1341         
1342         if(hits<0) printf("Too many objects in select buffer\n");       // XXX make error message
1343         
1344         return hits;
1345 }
1346
1347 /* ********************** local view operator ******************** */
1348
1349 static unsigned int free_localbit(void)
1350 {
1351         unsigned int lay;
1352         ScrArea *sa;
1353         bScreen *sc;
1354         
1355         lay= 0;
1356         
1357         /* sometimes we loose a localview: when an area is closed */
1358         /* check all areas: which localviews are in use? */
1359         for(sc= G.main->screen.first; sc; sc= sc->id.next) {
1360                 for(sa= sc->areabase.first; sa; sa= sa->next) {
1361                         SpaceLink *sl= sa->spacedata.first;
1362                         for(; sl; sl= sl->next) {
1363                                 if(sl->spacetype==SPACE_VIEW3D) {
1364                                         View3D *v3d= (View3D*) sl;
1365                                         lay |= v3d->lay;
1366                                 }
1367                         }
1368                 }
1369         }
1370         
1371         if( (lay & 0x01000000)==0) return 0x01000000;
1372         if( (lay & 0x02000000)==0) return 0x02000000;
1373         if( (lay & 0x04000000)==0) return 0x04000000;
1374         if( (lay & 0x08000000)==0) return 0x08000000;
1375         if( (lay & 0x10000000)==0) return 0x10000000;
1376         if( (lay & 0x20000000)==0) return 0x20000000;
1377         if( (lay & 0x40000000)==0) return 0x40000000;
1378         if( (lay & 0x80000000)==0) return 0x80000000;
1379         
1380         return 0;
1381 }
1382
1383 int ED_view3d_scene_layer_set(int lay, const int *values, int *active)
1384 {
1385         int i, tot= 0;
1386         
1387         /* ensure we always have some layer selected */
1388         for(i=0; i<20; i++)
1389                 if(values[i])
1390                         tot++;
1391         
1392         if(tot==0)
1393                 return lay;
1394         
1395         for(i=0; i<20; i++) {
1396                 
1397                 if (active) {
1398                         /* if this value has just been switched on, make that layer active */
1399                         if (values[i] && (lay & (1<<i))==0) {
1400                                 *active = (1<<i);
1401                         }
1402                 }
1403                         
1404                 if (values[i]) lay |= (1<<i);
1405                 else lay &= ~(1<<i);
1406         }
1407         
1408         /* ensure always an active layer */
1409         if (active && (lay & *active)==0) {
1410                 for(i=0; i<20; i++) {
1411                         if(lay & (1<<i)) {
1412                                 *active= 1<<i;
1413                                 break;
1414                         }
1415                 }
1416         }
1417         
1418         return lay;
1419 }
1420
1421 static void initlocalview(Scene *scene, ScrArea *sa)
1422 {
1423         View3D *v3d= sa->spacedata.first;
1424         Base *base;
1425         float size = 0.0, min[3], max[3], box[3];
1426         unsigned int locallay;
1427         int ok=0;
1428
1429         if(v3d->localvd) return;
1430
1431         INIT_MINMAX(min, max);
1432
1433         locallay= free_localbit();
1434
1435         if(locallay==0) {
1436                 printf("Sorry, no more than 8 localviews\n");   // XXX error 
1437                 ok= 0;
1438         }
1439         else {
1440                 if(scene->obedit) {
1441                         minmax_object(scene->obedit, min, max);
1442                         
1443                         ok= 1;
1444                 
1445                         BASACT->lay |= locallay;
1446                         scene->obedit->lay= BASACT->lay;
1447                 }
1448                 else {
1449                         for(base= FIRSTBASE; base; base= base->next) {
1450                                 if(TESTBASE(v3d, base))  {
1451                                         minmax_object(base->object, min, max);
1452                                         base->lay |= locallay;
1453                                         base->object->lay= base->lay;
1454                                         ok= 1;
1455                                 }
1456                         }
1457                 }
1458                 
1459                 box[0]= (max[0]-min[0]);
1460                 box[1]= (max[1]-min[1]);
1461                 box[2]= (max[2]-min[2]);
1462                 size= MAX3(box[0], box[1], box[2]);
1463                 if(size<=0.01) size= 0.01;
1464         }
1465         
1466         if(ok) {
1467                 ARegion *ar;
1468                 
1469                 v3d->localvd= MEM_mallocN(sizeof(View3D), "localview");
1470                 
1471                 memcpy(v3d->localvd, v3d, sizeof(View3D));
1472
1473                 for(ar= sa->regionbase.first; ar; ar= ar->next) {
1474                         if(ar->regiontype == RGN_TYPE_WINDOW) {
1475                                 RegionView3D *rv3d= ar->regiondata;
1476
1477                                 rv3d->localvd= MEM_mallocN(sizeof(RegionView3D), "localview region");
1478                                 memcpy(rv3d->localvd, rv3d, sizeof(RegionView3D));
1479                                 
1480                                 rv3d->ofs[0]= -(min[0]+max[0])/2.0;
1481                                 rv3d->ofs[1]= -(min[1]+max[1])/2.0;
1482                                 rv3d->ofs[2]= -(min[2]+max[2])/2.0;
1483
1484                                 rv3d->dist= size;
1485                                 /* perspective should be a bit farther away to look nice */
1486                                 if(rv3d->persp==RV3D_ORTHO)
1487                                         rv3d->dist*= 0.7;
1488
1489                                 // correction for window aspect ratio
1490                                 if(ar->winy>2 && ar->winx>2) {
1491                                         float asp= (float)ar->winx/(float)ar->winy;
1492                                         if(asp<1.0) asp= 1.0/asp;
1493                                         rv3d->dist*= asp;
1494                                 }
1495                                 
1496                                 if (rv3d->persp==RV3D_CAMOB) rv3d->persp= RV3D_PERSP;
1497                                 
1498                                 v3d->cursor[0]= -rv3d->ofs[0];
1499                                 v3d->cursor[1]= -rv3d->ofs[1];
1500                                 v3d->cursor[2]= -rv3d->ofs[2];
1501                         }
1502                 }
1503                 if (v3d->near> 0.1) v3d->near= 0.1;
1504                 
1505                 v3d->lay= locallay;
1506         }
1507         else {
1508                 /* clear flags */ 
1509                 for(base= FIRSTBASE; base; base= base->next) {
1510                         if( base->lay & locallay ) {
1511                                 base->lay-= locallay;
1512                                 if(base->lay==0) base->lay= v3d->layact;
1513                                 if(base->object != scene->obedit) base->flag |= SELECT;
1514                                 base->object->lay= base->lay;
1515                         }
1516                 }               
1517         }
1518
1519 }
1520
1521 static void restore_localviewdata(ScrArea *sa, int free)
1522 {
1523         ARegion *ar;
1524         View3D *v3d= sa->spacedata.first;
1525         
1526         if(v3d->localvd==NULL) return;
1527         
1528         v3d->near= v3d->localvd->near;
1529         v3d->far= v3d->localvd->far;
1530         v3d->lay= v3d->localvd->lay;
1531         v3d->layact= v3d->localvd->layact;
1532         v3d->drawtype= v3d->localvd->drawtype;
1533         v3d->camera= v3d->localvd->camera;
1534         
1535         if(free) {
1536                 MEM_freeN(v3d->localvd);
1537                 v3d->localvd= NULL;
1538         }
1539         
1540         for(ar= sa->regionbase.first; ar; ar= ar->next) {
1541                 if(ar->regiontype == RGN_TYPE_WINDOW) {
1542                         RegionView3D *rv3d= ar->regiondata;
1543                         
1544                         if(rv3d->localvd) {
1545                                 rv3d->dist= rv3d->localvd->dist;
1546                                 VECCOPY(rv3d->ofs, rv3d->localvd->ofs);
1547                                 QUATCOPY(rv3d->viewquat, rv3d->localvd->viewquat);
1548                                 rv3d->view= rv3d->localvd->view;
1549                                 rv3d->persp= rv3d->localvd->persp;
1550                                 rv3d->camzoom= rv3d->localvd->camzoom;
1551
1552                                 if(free) {
1553                                         MEM_freeN(rv3d->localvd);
1554                                         rv3d->localvd= NULL;
1555                                 }
1556                         }
1557                 }
1558         }
1559 }
1560
1561 static void endlocalview(Scene *scene, ScrArea *sa)
1562 {
1563         View3D *v3d= sa->spacedata.first;
1564         struct Base *base;
1565         unsigned int locallay;
1566         
1567         if(v3d->localvd) {
1568                 
1569                 locallay= v3d->lay & 0xFF000000;
1570                 
1571                 restore_localviewdata(sa, 1); // 1 = free
1572
1573                 /* for when in other window the layers have changed */
1574                 if(v3d->scenelock) v3d->lay= scene->lay;
1575                 
1576                 for(base= FIRSTBASE; base; base= base->next) {
1577                         if( base->lay & locallay ) {
1578                                 base->lay-= locallay;
1579                                 if(base->lay==0) base->lay= v3d->layact;
1580                                 if(base->object != scene->obedit) {
1581                                         base->flag |= SELECT;
1582                                         base->object->flag |= SELECT;
1583                                 }
1584                                 base->object->lay= base->lay;
1585                         }
1586                 }
1587         } 
1588 }
1589
1590 static int localview_exec(bContext *C, wmOperator *unused)
1591 {
1592         View3D *v3d= CTX_wm_view3d(C);
1593         
1594         if(v3d->localvd)
1595                 endlocalview(CTX_data_scene(C), CTX_wm_area(C));
1596         else
1597                 initlocalview(CTX_data_scene(C), CTX_wm_area(C));
1598         
1599         ED_area_tag_redraw(CTX_wm_area(C));
1600         
1601         return OPERATOR_FINISHED;
1602 }
1603
1604 void VIEW3D_OT_localview(wmOperatorType *ot)
1605 {
1606         
1607         /* identifiers */
1608         ot->name= "Local View";
1609         ot->description= "Toggle display of selected object(s) separately and centered in view";
1610         ot->idname= "VIEW3D_OT_localview";
1611         
1612         /* api callbacks */
1613         ot->exec= localview_exec;
1614         
1615         ot->poll= ED_operator_view3d_active;
1616 }
1617
1618 #if GAMEBLENDER == 1
1619
1620 static ListBase queue_back;
1621 static void SaveState(bContext *C)
1622 {
1623         wmWindow *win= CTX_wm_window(C);
1624         Object *obact = CTX_data_active_object(C);
1625         
1626         glPushAttrib(GL_ALL_ATTRIB_BITS);
1627
1628         if(obact && obact->mode & OB_MODE_TEXTURE_PAINT)
1629                 GPU_paint_set_mipmap(1);
1630         
1631         queue_back= win->queue;
1632         
1633         win->queue.first= win->queue.last= NULL;
1634         
1635         //XXX waitcursor(1);
1636 }
1637
1638 static void RestoreState(bContext *C)
1639 {
1640         wmWindow *win= CTX_wm_window(C);
1641         Object *obact = CTX_data_active_object(C);
1642         
1643         if(obact && obact->mode & OB_MODE_TEXTURE_PAINT)
1644                 GPU_paint_set_mipmap(0);
1645
1646         //XXX curarea->win_swap = 0;
1647         //XXX curarea->head_swap=0;
1648         //XXX allqueue(REDRAWVIEW3D, 1);
1649         //XXX allqueue(REDRAWBUTSALL, 0);
1650         //XXX reset_slowparents();
1651         //XXX waitcursor(0);
1652         //XXX G.qual= 0;
1653         
1654         win->queue= queue_back;
1655         
1656         GPU_state_init();
1657
1658         glPopAttrib();
1659 }
1660
1661 /* was space_set_commmandline_options in 2.4x */
1662 void game_set_commmandline_options(GameData *gm)
1663 {
1664         SYS_SystemHandle syshandle;
1665         int test;
1666
1667         if ( (syshandle = SYS_GetSystem()) ) {
1668                 /* User defined settings */
1669                 test= (U.gameflags & USER_DISABLE_MIPMAP);
1670                 GPU_set_mipmap(!test);
1671                 SYS_WriteCommandLineInt(syshandle, "nomipmap", test);
1672
1673                 /* File specific settings: */
1674                 /* Only test the first one. These two are switched
1675                  * simultaneously. */
1676                 test= (gm->flag & GAME_SHOW_FRAMERATE);
1677                 SYS_WriteCommandLineInt(syshandle, "show_framerate", test);
1678                 SYS_WriteCommandLineInt(syshandle, "show_profile", test);
1679
1680                 test = (gm->flag & GAME_SHOW_DEBUG_PROPS);
1681                 SYS_WriteCommandLineInt(syshandle, "show_properties", test);
1682
1683                 test= (gm->flag & GAME_SHOW_PHYSICS);
1684                 SYS_WriteCommandLineInt(syshandle, "show_physics", test);
1685
1686                 test= (gm->flag & GAME_ENABLE_ALL_FRAMES);
1687                 SYS_WriteCommandLineInt(syshandle, "fixedtime", test);
1688
1689                 test= (gm->flag & GAME_ENABLE_ANIMATION_RECORD);
1690                 SYS_WriteCommandLineInt(syshandle, "animation_record", test);
1691
1692                 test= (gm->flag & GAME_IGNORE_DEPRECATION_WARNINGS);
1693                 SYS_WriteCommandLineInt(syshandle, "ignore_deprecation_warnings", test);
1694
1695                 test= (gm->matmode == GAME_MAT_MULTITEX);
1696                 SYS_WriteCommandLineInt(syshandle, "blender_material", test);
1697                 test= (gm->matmode == GAME_MAT_GLSL);
1698                 SYS_WriteCommandLineInt(syshandle, "blender_glsl_material", test);
1699                 test= (gm->flag & GAME_DISPLAY_LISTS);
1700                 SYS_WriteCommandLineInt(syshandle, "displaylists", test);
1701
1702
1703         }
1704 }
1705
1706 /* maybe we need this defined somewhere else */
1707 extern void StartKetsjiShell(struct bContext *C, struct ARegion *ar, rcti *cam_frame, int always_use_expand_framing);
1708
1709 #endif // GAMEBLENDER == 1
1710
1711 int game_engine_poll(bContext *C)
1712 {
1713         /* we need a context and area to launch BGE
1714         it's a temporary solution to avoid crash at load time
1715         if we try to auto run the BGE. Ideally we want the
1716         context to be set as soon as we load the file. */
1717
1718         if(CTX_wm_window(C)==NULL) return 0;
1719         if(CTX_wm_screen(C)==NULL) return 0;
1720         if(CTX_wm_area(C)==NULL) return 0;
1721
1722         if(CTX_data_mode_enum(C)!=CTX_MODE_OBJECT)
1723                 return 0;
1724
1725         return 1;
1726 }
1727
1728 int ED_view3d_context_activate(bContext *C)
1729 {
1730         bScreen *sc= CTX_wm_screen(C);
1731         ScrArea *sa= CTX_wm_area(C);
1732         ARegion *ar;
1733         RegionView3D *rv3d;
1734
1735         /* sa can be NULL when called from python */
1736         if(sa==NULL || sa->spacetype != SPACE_VIEW3D)
1737                 for(sa=sc->areabase.first; sa; sa= sa->next)
1738                         if(sa->spacetype==SPACE_VIEW3D)
1739                                 break;
1740
1741         if(!sa)
1742                 return 0;
1743         
1744         for(ar=sa->regionbase.first; ar; ar=ar->next)
1745                 if(ar->regiontype == RGN_TYPE_WINDOW)
1746                         break;
1747         
1748         if(!ar)
1749                 return 0;
1750         
1751         // bad context switch ..
1752         CTX_wm_area_set(C, sa);
1753         CTX_wm_region_set(C, ar);
1754         rv3d= ar->regiondata;
1755
1756         return 1;
1757 }
1758
1759 static int game_engine_exec(bContext *C, wmOperator *op)
1760 {
1761 #if GAMEBLENDER == 1
1762         Scene *startscene = CTX_data_scene(C);
1763         ScrArea *sa, *prevsa= CTX_wm_area(C);
1764         ARegion *ar, *prevar= CTX_wm_region(C);
1765         wmWindow *prevwin= CTX_wm_window(C);
1766         RegionView3D *rv3d;
1767         rcti cam_frame;
1768
1769         // bad context switch ..
1770         if(!ED_view3d_context_activate(C))
1771                 return OPERATOR_CANCELLED;
1772         
1773         rv3d= CTX_wm_region_view3d(C);
1774         sa= CTX_wm_area(C);
1775         ar= CTX_wm_region(C);
1776
1777         view3d_operator_needs_opengl(C);
1778         
1779         game_set_commmandline_options(&startscene->gm);
1780
1781         if(rv3d->persp==RV3D_CAMOB && startscene->gm.framing.type == SCE_GAMEFRAMING_BARS && startscene->gm.stereoflag != STEREO_DOME) { /* Letterbox */
1782                 rctf cam_framef;
1783                 calc_viewborder(startscene, ar, rv3d, CTX_wm_view3d(C), &cam_framef);
1784                 cam_frame.xmin = cam_framef.xmin + ar->winrct.xmin;
1785                 cam_frame.xmax = cam_framef.xmax + ar->winrct.xmin;
1786                 cam_frame.ymin = cam_framef.ymin + ar->winrct.ymin;
1787                 cam_frame.ymax = cam_framef.ymax + ar->winrct.ymin;
1788                 BLI_isect_rcti(&ar->winrct, &cam_frame, &cam_frame);
1789         }
1790         else {
1791                 cam_frame.xmin = ar->winrct.xmin;
1792                 cam_frame.xmax = ar->winrct.xmax;
1793                 cam_frame.ymin = ar->winrct.ymin;
1794                 cam_frame.ymax = ar->winrct.ymax;
1795         }
1796
1797
1798         SaveState(C);
1799
1800         StartKetsjiShell(C, ar, &cam_frame, 1);
1801         
1802         /* restore context, in case it changed in the meantime, for
1803            example by working in another window or closing it */
1804         CTX_wm_region_set(C, prevar);
1805         CTX_wm_window_set(C, prevwin);
1806         CTX_wm_area_set(C, prevsa);
1807         RestoreState(C);
1808
1809         //XXX restore_all_scene_cfra(scene_cfra_store);
1810         set_scene_bg(startscene);
1811         //XXX scene_update_for_newframe(G.scene, G.scene->lay);
1812         
1813         ED_area_tag_redraw(CTX_wm_area(C));
1814
1815         return OPERATOR_FINISHED;
1816 #else
1817         BKE_report(op->reports, RPT_ERROR, "Game engine is disabled in this build.");
1818         return OPERATOR_CANCELLED;
1819 #endif
1820 }
1821
1822 void VIEW3D_OT_game_start(wmOperatorType *ot)
1823 {
1824         
1825         /* identifiers */
1826         ot->name= "Start Game Engine";
1827         ot->description= "Start game engine";
1828         ot->idname= "VIEW3D_OT_game_start";
1829         
1830         /* api callbacks */
1831         ot->exec= game_engine_exec;
1832         
1833         ot->poll= game_engine_poll;
1834 }
1835
1836
1837 /* NOTE: these defines are saved in keymap files, do not change values but just add new ones */
1838 #define FLY_MODAL_CANCEL                        1
1839 #define FLY_MODAL_CONFIRM                       2
1840 #define FLY_MODAL_ACCELERATE            3
1841 #define FLY_MODAL_DECELERATE            4
1842 #define FLY_MODAL_PAN_ENABLE            5
1843 #define FLY_MODAL_PAN_DISABLE           6
1844 #define FLY_MODAL_DIR_FORWARD           7
1845 #define FLY_MODAL_DIR_BACKWARD          8
1846 #define FLY_MODAL_DIR_LEFT                      9
1847 #define FLY_MODAL_DIR_RIGHT                     10
1848 #define FLY_MODAL_DIR_UP                        11
1849 #define FLY_MODAL_DIR_DOWN                      12
1850 #define FLY_MODAL_AXIS_LOCK_X           13
1851 #define FLY_MODAL_AXIS_LOCK_Z           14
1852 #define FLY_MODAL_PRECISION_ENABLE      15
1853 #define FLY_MODAL_PRECISION_DISABLE     16
1854
1855 /* called in transform_ops.c, on each regeneration of keymaps  */
1856 void fly_modal_keymap(wmKeyConfig *keyconf)
1857 {
1858         static EnumPropertyItem modal_items[] = {
1859         {FLY_MODAL_CANCEL,      "CANCEL", 0, "Cancel", ""},
1860         {FLY_MODAL_CONFIRM,     "CONFIRM", 0, "Confirm", ""},
1861         {FLY_MODAL_ACCELERATE, "ACCELERATE", 0, "Accelerate", ""},
1862         {FLY_MODAL_DECELERATE, "DECELERATE", 0, "Decelerate", ""},
1863
1864         {FLY_MODAL_PAN_ENABLE,  "PAN_ENABLE", 0, "Pan Enable", ""},
1865         {FLY_MODAL_PAN_DISABLE, "PAN_DISABLE", 0, "Pan Disable", ""},
1866
1867         {FLY_MODAL_DIR_FORWARD, "FORWARD", 0, "Fly Forward", ""},
1868         {FLY_MODAL_DIR_BACKWARD,"BACKWARD", 0, "Fly Backward", ""},
1869         {FLY_MODAL_DIR_LEFT,    "LEFT", 0, "Fly Left", ""},
1870         {FLY_MODAL_DIR_RIGHT,   "RIGHT", 0, "Fly Right", ""},
1871         {FLY_MODAL_DIR_UP,              "UP", 0, "Fly Up", ""},
1872         {FLY_MODAL_DIR_DOWN,    "DOWN", 0, "Fly Down", ""},
1873
1874         {FLY_MODAL_AXIS_LOCK_X, "AXIS_LOCK_X", 0, "X Axis Correction", "X axis correction (toggle)"},
1875         {FLY_MODAL_AXIS_LOCK_Z, "AXIS_LOCK_Z", 0, "X Axis Correction", "Z axis correction (toggle)"},
1876
1877         {FLY_MODAL_PRECISION_ENABLE,    "PRECISION_ENABLE", 0, "Precision Enable", ""},
1878         {FLY_MODAL_PRECISION_DISABLE,   "PRECISION_DISABLE", 0, "Precision Disable", ""},
1879
1880         {0, NULL, 0, NULL, NULL}};
1881
1882         wmKeyMap *keymap= WM_modalkeymap_get(keyconf, "View3D Fly Modal");
1883
1884         /* this function is called for each spacetype, only needs to add map once */
1885         if(keymap) return;
1886
1887         keymap= WM_modalkeymap_add(keyconf, "View3D Fly Modal", modal_items);
1888
1889         /* items for modal map */
1890         WM_modalkeymap_add_item(keymap, ESCKEY,    KM_PRESS, KM_ANY, 0, FLY_MODAL_CANCEL);
1891         WM_modalkeymap_add_item(keymap, RIGHTMOUSE, KM_ANY, KM_ANY, 0, FLY_MODAL_CANCEL);
1892
1893         WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_ANY, KM_ANY, 0, FLY_MODAL_CONFIRM);
1894         WM_modalkeymap_add_item(keymap, RETKEY, KM_PRESS, KM_ANY, 0, FLY_MODAL_CONFIRM);
1895         WM_modalkeymap_add_item(keymap, SPACEKEY, KM_PRESS, KM_ANY, 0, FLY_MODAL_CONFIRM);
1896         WM_modalkeymap_add_item(keymap, PADENTER, KM_PRESS, KM_ANY, 0, FLY_MODAL_CONFIRM);
1897
1898         WM_modalkeymap_add_item(keymap, PADPLUSKEY, KM_PRESS, 0, 0, FLY_MODAL_ACCELERATE);
1899         WM_modalkeymap_add_item(keymap, PADMINUS, KM_PRESS, 0, 0, FLY_MODAL_DECELERATE);
1900         WM_modalkeymap_add_item(keymap, WHEELUPMOUSE, KM_PRESS, 0, 0, FLY_MODAL_ACCELERATE);
1901         WM_modalkeymap_add_item(keymap, WHEELDOWNMOUSE, KM_PRESS, 0, 0, FLY_MODAL_DECELERATE);
1902
1903         WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_PRESS, KM_ANY, 0, FLY_MODAL_PAN_ENABLE);
1904         WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_RELEASE, KM_ANY, 0, FLY_MODAL_PAN_DISABLE); /* XXX - Bug in the event system, middle mouse release doesnt work */
1905
1906         /* WASD */
1907         WM_modalkeymap_add_item(keymap, WKEY, KM_PRESS, 0, 0, FLY_MODAL_DIR_FORWARD);
1908         WM_modalkeymap_add_item(keymap, SKEY, KM_PRESS, 0, 0, FLY_MODAL_DIR_BACKWARD);
1909         WM_modalkeymap_add_item(keymap, AKEY, KM_PRESS, 0, 0, FLY_MODAL_DIR_LEFT);
1910         WM_modalkeymap_add_item(keymap, DKEY, KM_PRESS, 0, 0, FLY_MODAL_DIR_RIGHT);
1911         WM_modalkeymap_add_item(keymap, RKEY, KM_PRESS, 0, 0, FLY_MODAL_DIR_UP);
1912         WM_modalkeymap_add_item(keymap, FKEY, KM_PRESS, 0, 0, FLY_MODAL_DIR_DOWN);
1913
1914         WM_modalkeymap_add_item(keymap, XKEY, KM_PRESS, 0, 0, FLY_MODAL_AXIS_LOCK_X);
1915         WM_modalkeymap_add_item(keymap, ZKEY, KM_PRESS, 0, 0, FLY_MODAL_AXIS_LOCK_Z);
1916
1917         WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_PRESS, KM_ANY, 0, FLY_MODAL_PRECISION_ENABLE);
1918         WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_RELEASE, KM_ANY, 0, FLY_MODAL_PRECISION_DISABLE);
1919
1920         /* assign map to operators */
1921         WM_modalkeymap_assign(keymap, "VIEW3D_OT_fly");
1922
1923 }
1924
1925 typedef struct FlyInfo {
1926         /* context stuff */
1927         RegionView3D *rv3d;
1928         View3D *v3d;
1929         ARegion *ar;
1930         Scene *scene;
1931
1932         wmTimer *timer; /* needed for redraws */
1933
1934         short state;
1935         short use_precision;
1936         short redraw;
1937         short mval[2];
1938
1939         /* fly state state */
1940         float speed; /* the speed the view is moving per redraw */
1941         short axis; /* Axis index to move allong by default Z to move allong the view */
1942         short pan_view; /* when true, pan the view instead of rotating */
1943
1944         /* relative view axis locking - xlock, zlock
1945         0; disabled
1946         1; enabled but not checking because mouse hasnt moved outside the margin since locking was checked an not needed
1947            when the mouse moves, locking is set to 2 so checks are done.
1948         2; mouse moved and checking needed, if no view altering is donem its changed back to 1 */
1949         short xlock, zlock;
1950         float xlock_momentum, zlock_momentum; /* nicer dynamics */
1951         float grid; /* world scale 1.0 default */
1952
1953         /* root most parent */
1954         Object *root_parent;
1955
1956         /* backup values */
1957         float dist_backup; /* backup the views distance since we use a zero dist for fly mode */
1958         float ofs_backup[3]; /* backup the views offset incase the user cancels flying in non camera mode */
1959         float rot_backup[4]; /* backup the views quat incase the user cancels flying in non camera mode. (quat for view, eul for camera) */
1960         short persp_backup; /* remember if were ortho or not, only used for restoring the view if it was a ortho view */
1961
1962         void *obtfm; /* backup the objects transform */
1963
1964         /* compare between last state */
1965         double time_lastwheel; /* used to accelerate when using the mousewheel a lot */
1966         double time_lastdraw; /* time between draws */
1967
1968         /* use for some lag */
1969         float dvec_prev[3]; /* old for some lag */
1970
1971 } FlyInfo;
1972
1973 /* FlyInfo->state */
1974 #define FLY_RUNNING             0
1975 #define FLY_CANCEL              1
1976 #define FLY_CONFIRM             2
1977
1978 static int initFlyInfo (bContext *C, FlyInfo *fly, wmOperator *op, wmEvent *event)
1979 {
1980         float upvec[3]; // tmp
1981         float mat[3][3];
1982
1983         fly->rv3d= CTX_wm_region_view3d(C);
1984         fly->v3d = CTX_wm_view3d(C);
1985         fly->ar = CTX_wm_region(C);
1986         fly->scene= CTX_data_scene(C);
1987
1988         if(fly->rv3d->persp==RV3D_CAMOB && fly->v3d->camera->id.lib) {
1989                 BKE_report(op->reports, RPT_ERROR, "Cannot fly a camera from an external library");
1990                 return FALSE;
1991         }
1992
1993         if(fly->v3d->ob_centre) {
1994                 BKE_report(op->reports, RPT_ERROR, "Cannot fly when the view is locked to an object");
1995                 return FALSE;
1996         }
1997
1998         if(fly->rv3d->persp==RV3D_CAMOB && fly->v3d->camera->constraints.first) {
1999                 BKE_report(op->reports, RPT_ERROR, "Cannot fly an object with constraints");
2000                 return FALSE;
2001         }
2002
2003         fly->state= FLY_RUNNING;
2004         fly->speed= 0.0f;
2005         fly->axis= 2;
2006         fly->pan_view= FALSE;
2007         fly->xlock= FALSE;
2008         fly->zlock= FALSE;
2009         fly->xlock_momentum=0.0f;
2010         fly->zlock_momentum=0.0f;
2011         fly->grid= 1.0f;
2012         fly->use_precision= 0;
2013
2014         fly->dvec_prev[0]= fly->dvec_prev[1]= fly->dvec_prev[2]= 0.0f;
2015
2016         fly->timer= WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, 0.01f);
2017
2018         fly->mval[0] = event->x - fly->ar->winrct.xmin;
2019         fly->mval[1] = event->y - fly->ar->winrct.ymin;
2020
2021
2022         fly->time_lastdraw= fly->time_lastwheel= PIL_check_seconds_timer();
2023
2024         fly->rv3d->rflag |= RV3D_FLYMODE|RV3D_NAVIGATING; /* so we draw the corner margins */
2025
2026         /* detect weather to start with Z locking */
2027         upvec[0]=1.0f; upvec[1]=0.0f; upvec[2]=0.0f;
2028         copy_m3_m4(mat, fly->rv3d->viewinv);
2029         mul_m3_v3(mat, upvec);
2030         if (fabs(upvec[2]) < 0.1)
2031                 fly->zlock = 1;
2032         upvec[0]=0; upvec[1]=0; upvec[2]=0;
2033
2034         fly->persp_backup= fly->rv3d->persp;
2035         fly->dist_backup= fly->rv3d->dist;
2036         if (fly->rv3d->persp==RV3D_CAMOB) {
2037                 Object *ob_back;
2038                 if((fly->root_parent=fly->v3d->camera->parent)) {
2039                         while(fly->root_parent->parent)
2040                                 fly->root_parent= fly->root_parent->parent;
2041                         ob_back= fly->root_parent;
2042                 }
2043                 else {
2044                         ob_back= fly->v3d->camera;
2045                 }
2046
2047                 /* store the original camera loc and rot */
2048                 /* TODO. axis angle etc */
2049
2050                 fly->obtfm= object_tfm_backup(ob_back);
2051
2052                 where_is_object(fly->scene, fly->v3d->camera);
2053                 negate_v3_v3(fly->rv3d->ofs, fly->v3d->camera->obmat[3]);
2054
2055                 fly->rv3d->dist=0.0;
2056         } else {
2057                 /* perspective or ortho */
2058                 if (fly->rv3d->persp==RV3D_ORTHO)
2059                         fly->rv3d->persp= RV3D_PERSP; /*if ortho projection, make perspective */
2060                 QUATCOPY(fly->rot_backup, fly->rv3d->viewquat);
2061                 copy_v3_v3(fly->ofs_backup, fly->rv3d->ofs);
2062                 fly->rv3d->dist= 0.0f;
2063
2064                 upvec[2]= fly->dist_backup; /*x and y are 0*/
2065                 mul_m3_v3(mat, upvec);
2066                 sub_v3_v3(fly->rv3d->ofs, upvec);
2067                 /*Done with correcting for the dist*/
2068         }
2069
2070         
2071         /* center the mouse, probably the UI mafia are against this but without its quite annoying */
2072         WM_cursor_warp(CTX_wm_window(C), fly->ar->winrct.xmin + fly->ar->winx/2, fly->ar->winrct.ymin + fly->ar->winy/2);
2073         
2074         return 1;
2075 }
2076
2077 static int flyEnd(bContext *C, FlyInfo *fly)
2078 {
2079         RegionView3D *rv3d= fly->rv3d;
2080         View3D *v3d = fly->v3d;
2081
2082         float upvec[3];
2083
2084         if(fly->state == FLY_RUNNING)
2085                 return OPERATOR_RUNNING_MODAL;
2086
2087         WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), fly->timer);
2088
2089         rv3d->dist= fly->dist_backup;
2090
2091         if (fly->state == FLY_CANCEL) {
2092         /* Revert to original view? */
2093                 if (fly->persp_backup==RV3D_CAMOB) { /* a camera view */
2094                         Object *ob_back;
2095                         if(fly->root_parent)ob_back= fly->root_parent;
2096                         else                            ob_back= fly->v3d->camera;
2097
2098                         /* store the original camera loc and rot */
2099                         object_tfm_restore(ob_back, fly->obtfm);
2100
2101                         DAG_id_flush_update(&ob_back->id, OB_RECALC_OB);
2102                 } else {
2103                         /* Non Camera we need to reset the view back to the original location bacause the user canceled*/
2104                         QUATCOPY(rv3d->viewquat, fly->rot_backup);
2105                         VECCOPY(rv3d->ofs, fly->ofs_backup);
2106                         rv3d->persp= fly->persp_backup;
2107                 }
2108         }
2109         else if (fly->persp_backup==RV3D_CAMOB) {       /* camera */
2110                 float mat3[3][3];
2111                 if(fly->root_parent) {
2112                         DAG_id_flush_update(&fly->root_parent->id, OB_RECALC_OB);
2113                 }
2114                 else {
2115                         copy_m3_m4(mat3, v3d->camera->obmat);
2116                         object_mat3_to_rot(v3d->camera, mat3, TRUE);
2117                         DAG_id_flush_update(&v3d->camera->id, OB_RECALC_OB);
2118                 }
2119
2120 #if 0 //XXX2.5
2121                 if (IS_AUTOKEY_MODE(NORMAL)) {
2122                         allqueue(REDRAWIPO, 0);
2123                         allspace(REMAKEIPO, 0);
2124                         allqueue(REDRAWNLA, 0);
2125                         allqueue(REDRAWTIME, 0);
2126                 }
2127 #endif
2128         }
2129         else { /* not camera */
2130                 /* Apply the fly mode view */
2131                 /*restore the dist*/
2132                 float mat[3][3];
2133                 upvec[0]= upvec[1]= 0;
2134                 upvec[2]= fly->dist_backup; /*x and y are 0*/
2135                 copy_m3_m4(mat, rv3d->viewinv);
2136                 mul_m3_v3(mat, upvec);
2137                 add_v3_v3(rv3d->ofs, upvec);
2138                 /*Done with correcting for the dist */
2139         }
2140
2141         rv3d->rflag &= ~(RV3D_FLYMODE|RV3D_NAVIGATING);
2142 //XXX2.5        BIF_view3d_previewrender_signal(fly->sa, PR_DBASE|PR_DISPRECT); /* not working at the moment not sure why */
2143
2144         if(fly->obtfm)
2145                 MEM_freeN(fly->obtfm);
2146
2147         if(fly->state == FLY_CONFIRM) {
2148                 MEM_freeN(fly);
2149                 return OPERATOR_FINISHED;
2150         }
2151
2152         MEM_freeN(fly);
2153         return OPERATOR_CANCELLED;
2154 }
2155
2156 static void flyEvent(FlyInfo *fly, wmEvent *event)
2157 {
2158         if (event->type == TIMER && event->customdata == fly->timer) {
2159                 fly->redraw = 1;
2160         }
2161         else if (event->type == MOUSEMOVE) {
2162                 fly->mval[0] = event->x - fly->ar->winrct.xmin;
2163                 fly->mval[1] = event->y - fly->ar->winrct.ymin;
2164         } /* handle modal keymap first */
2165         else if (event->type == EVT_MODAL_MAP) {
2166                 switch (event->val) {
2167                         case FLY_MODAL_CANCEL:
2168                                 fly->state = FLY_CANCEL;
2169                                 break;
2170                         case FLY_MODAL_CONFIRM:
2171                                 fly->state = FLY_CONFIRM;
2172                                 break;
2173
2174                         case FLY_MODAL_ACCELERATE:
2175                         {
2176                                 double time_currwheel;
2177                                 float time_wheel;
2178
2179                                 time_currwheel= PIL_check_seconds_timer();
2180                                 time_wheel = (float)(time_currwheel - fly->time_lastwheel);
2181                                 fly->time_lastwheel = time_currwheel;
2182                                 /*printf("Wheel %f\n", time_wheel);*/
2183                                 /*Mouse wheel delays range from 0.5==slow to 0.01==fast*/
2184                                 time_wheel = 1+ (10 - (20*MIN2(time_wheel, 0.5))); /* 0-0.5 -> 0-5.0 */
2185
2186                                 if (fly->speed<0.0f) fly->speed= 0.0f;
2187                                 else {
2188                                         if (event->shift)
2189                                                 fly->speed+= fly->grid*time_wheel*0.1;
2190                                         else
2191                                                 fly->speed+= fly->grid*time_wheel;
2192                                 }
2193                                 break;
2194                         }
2195                         case FLY_MODAL_DECELERATE:
2196                         {
2197                                 double time_currwheel;
2198                                 float time_wheel;
2199
2200                                 time_currwheel= PIL_check_seconds_timer();
2201                                 time_wheel = (float)(time_currwheel - fly->time_lastwheel);
2202                                 fly->time_lastwheel = time_currwheel;
2203                                 time_wheel = 1+ (10 - (20*MIN2(time_wheel, 0.5))); /* 0-0.5 -> 0-5.0 */
2204
2205                                 if (fly->speed>0) fly->speed=0;
2206                                 else {
2207                                         if (event->shift)
2208                                                 fly->speed-= fly->grid*time_wheel*0.1;
2209                                         else
2210                                                 fly->speed-= fly->grid*time_wheel;
2211                                 }
2212                                 break;
2213                         }
2214                         case FLY_MODAL_PAN_ENABLE:
2215                                 fly->pan_view= TRUE;
2216                                 break;
2217                         case FLY_MODAL_PAN_DISABLE:
2218 //XXX2.5                warp_pointer(cent_orig[0], cent_orig[1]);
2219                                 fly->pan_view= FALSE;
2220                                 break;
2221
2222                                 /* impliment WASD keys */
2223                         case FLY_MODAL_DIR_FORWARD:
2224                                 if (fly->speed < 0.0f) fly->speed= -fly->speed; /* flip speed rather then stopping, game like motion */
2225                                 else fly->speed += fly->grid; /* increse like mousewheel if were already moving in that difection*/
2226                                 fly->axis= 2;
2227                                 break;
2228                         case FLY_MODAL_DIR_BACKWARD:
2229                                 if (fly->speed>0) fly->speed= -fly->speed;
2230                                 else fly->speed -= fly->grid;
2231                                 fly->axis= 2;
2232                                 break;
2233                         case FLY_MODAL_DIR_LEFT:
2234                                 if (fly->speed < 0.0f) fly->speed= -fly->speed;
2235                                 fly->axis= 0;
2236                                 break;
2237                         case FLY_MODAL_DIR_RIGHT:
2238                                 if (fly->speed > 0.0f) fly->speed= -fly->speed;
2239                                 fly->axis= 0;
2240                                 break;
2241
2242                         case FLY_MODAL_DIR_UP:
2243                                 if (fly->speed > 0.0f) fly->speed= -fly->speed;
2244                                 fly->axis= 1;
2245                                 break;
2246
2247                         case FLY_MODAL_DIR_DOWN:
2248                                 if (fly->speed < 0.0f) fly->speed= -fly->speed;
2249                                 fly->axis= 1;
2250                                 break;
2251
2252                         case FLY_MODAL_AXIS_LOCK_X:
2253                                 if (fly->xlock) fly->xlock=0;
2254                                 else {
2255                                         fly->xlock = 2;
2256                                         fly->xlock_momentum = 0.0;
2257                                 }
2258                                 break;
2259                         case FLY_MODAL_AXIS_LOCK_Z:
2260                                 if (fly->zlock) fly->zlock=0;
2261                                 else {
2262                                         fly->zlock = 2;
2263                                         fly->zlock_momentum = 0.0;
2264                                 }
2265                                 break;
2266
2267                         case FLY_MODAL_PRECISION_ENABLE:
2268                                 fly->use_precision= TRUE;
2269                                 break;
2270                         case FLY_MODAL_PRECISION_DISABLE:
2271                                 fly->use_precision= FALSE;
2272                                 break;
2273
2274                 }
2275         }
2276 }
2277
2278 static int flyApply(bContext *C, FlyInfo *fly)
2279 {
2280
2281 #define FLY_ROTATE_FAC 2.5f /* more is faster */
2282 #define FLY_ZUP_CORRECT_FAC 0.1f /* ammount to correct per step */
2283 #define FLY_ZUP_CORRECT_ACCEL 0.05f /* increase upright momentum each step */
2284
2285         /*
2286         fly mode - Shift+F
2287         a fly loop where the user can move move the view as if they are flying
2288         */
2289         RegionView3D *rv3d= fly->rv3d;
2290         View3D *v3d = fly->v3d;
2291         ARegion *ar = fly->ar;
2292         Scene *scene= fly->scene;
2293
2294         float prev_view_mat[4][4];
2295
2296         float mat[3][3], /* 3x3 copy of the view matrix so we can move allong the view axis */
2297         dvec[3]={0,0,0}, /* this is the direction thast added to the view offset per redraw */
2298
2299         /* Camera Uprighting variables */
2300         upvec[3]={0,0,0}, /* stores the view's up vector */
2301
2302         moffset[2], /* mouse offset from the views center */
2303         tmp_quat[4]; /* used for rotating the view */
2304
2305         int cent_orig[2], /* view center */
2306 //XXX- can avoid using //       cent[2], /* view center modified */
2307         xmargin, ymargin; /* x and y margin are define the safe area where the mouses movement wont rotate the view */
2308         unsigned char
2309         apply_rotation= 1; /* if the user presses shift they can look about without movinf the direction there looking*/
2310
2311         if(fly->root_parent)
2312                 view3d_persp_mat4(rv3d, prev_view_mat);
2313
2314         /* the dist defines a vector that is infront of the offset
2315         to rotate the view about.
2316         this is no good for fly mode because we
2317         want to rotate about the viewers center.
2318         but to correct the dist removal we must
2319         alter offset so the view doesn't jump. */
2320
2321         xmargin= ar->winx/20.0f;
2322         ymargin= ar->winy/20.0f;
2323
2324         cent_orig[0]= ar->winrct.xmin + ar->winx/2;
2325         cent_orig[1]= ar->winrct.ymin + ar->winy/2;
2326
2327         {
2328
2329                 /* mouse offset from the center */
2330                 moffset[0]= fly->mval[0]- ar->winx/2;
2331                 moffset[1]= fly->mval[1]- ar->winy/2;
2332
2333                 /* enforce a view margin */
2334                 if (moffset[0]>xmargin)                 moffset[0]-=xmargin;
2335                 else if (moffset[0] < -xmargin) moffset[0]+=xmargin;
2336                 else                                                    moffset[0]=0;
2337
2338                 if (moffset[1]>ymargin)                 moffset[1]-=ymargin;
2339                 else if (moffset[1] < -ymargin) moffset[1]+=ymargin;
2340                 else                                                    moffset[1]=0;
2341
2342
2343                 /* scale the mouse movement by this value - scales mouse movement to the view size
2344                  * moffset[0]/(ar->winx-xmargin*2) - window size minus margin (same for y)
2345                  *
2346                  * the mouse moves isnt linear */
2347
2348                 if(moffset[0]) {
2349                         moffset[0] /= ar->winx - (xmargin*2);
2350                         moffset[0] *= fabs(moffset[0]);
2351                 }
2352
2353                 if(moffset[1]) {
2354                         moffset[1] /= ar->winy - (ymargin*2);
2355                         moffset[1] *= fabs(moffset[1]);
2356                 }
2357
2358                 /* Should we redraw? */
2359                 if(fly->speed != 0.0f || moffset[0] || moffset[1] || fly->zlock || fly->xlock || dvec[0] || dvec[1] || dvec[2] ) {
2360                         float dvec_tmp[3];
2361                         double time_current, time_redraw; /*time how fast it takes for us to redraw, this is so simple scenes dont fly too fast */
2362                         float time_redraw_clamped;
2363
2364                         time_current= PIL_check_seconds_timer();
2365                         time_redraw= (float)(time_current - fly->time_lastdraw);
2366                         time_redraw_clamped= MIN2(0.05f, time_redraw); /* clamt the redraw time to avoid jitter in roll correction */
2367                         fly->time_lastdraw= time_current;
2368                         /*fprintf(stderr, "%f\n", time_redraw);*/ /* 0.002 is a small redraw 0.02 is larger */
2369
2370                         /* Scale the time to use shift to scale the speed down- just like
2371                         shift slows many other areas of blender down */
2372                         if (fly->use_precision)
2373                                 fly->speed= fly->speed * (1.0f-time_redraw_clamped);
2374
2375                         copy_m3_m4(mat, rv3d->viewinv);
2376
2377                         if (fly->pan_view==TRUE) {
2378                                 /* pan only */
2379                                 dvec_tmp[0]= -moffset[0];
2380                                 dvec_tmp[1]= -moffset[1];
2381                                 dvec_tmp[2]= 0;
2382
2383                                 if (fly->use_precision) {
2384                                         dvec_tmp[0] *= 0.1;
2385                                         dvec_tmp[1] *= 0.1;
2386                                 }
2387
2388                                 mul_m3_v3(mat, dvec_tmp);
2389                                 mul_v3_fl(dvec_tmp, time_redraw*200.0 * fly->grid);
2390
2391                         } else {
2392                                 float roll; /* similar to the angle between the camera's up and the Z-up, but its very rough so just roll*/
2393
2394                                 /* rotate about the X axis- look up/down */
2395                                 if (moffset[1]) {
2396                                         upvec[0]=1;
2397                                         upvec[1]=0;
2398                                         upvec[2]=0;
2399                                         mul_m3_v3(mat, upvec);
2400                                         axis_angle_to_quat( tmp_quat, upvec, (float)moffset[1] * time_redraw * -FLY_ROTATE_FAC); /* Rotate about the relative up vec */
2401                                         mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, tmp_quat);
2402
2403                                         if (fly->xlock) fly->xlock = 2; /*check for rotation*/
2404                                         if (fly->zlock) fly->zlock = 2;
2405                                         fly->xlock_momentum= 0.0f;
2406                                 }
2407
2408                                 /* rotate about the Y axis- look left/right */
2409                                 if (moffset[0]) {
2410
2411                                         /* if we're upside down invert the moffset */
2412                                         upvec[0]=0;
2413                                         upvec[1]=1;
2414                                         upvec[2]=0;
2415                                         mul_m3_v3(mat, upvec);
2416
2417                                         if(upvec[2] < 0.0f)
2418                                                 moffset[0]= -moffset[0];
2419
2420                                         /* make the lock vectors */
2421                                         if (fly->zlock) {
2422                                                 upvec[0]=0;
2423                                                 upvec[1]=0;
2424                                                 upvec[2]=1;
2425                                         } else {
2426                                                 upvec[0]=0;
2427                                                 upvec[1]=1;
2428                                                 upvec[2]=0;
2429                                                 mul_m3_v3(mat, upvec);
2430                                         }
2431
2432                                         axis_angle_to_quat( tmp_quat, upvec, (float)moffset[0] * time_redraw * FLY_ROTATE_FAC); /* Rotate about the relative up vec */
2433                                         mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, tmp_quat);
2434
2435                                         if (fly->xlock) fly->xlock = 2;/*check for rotation*/
2436                                         if (fly->zlock) fly->zlock = 2;
2437                                 }
2438
2439                                 if (fly->zlock==2) {
2440                                         upvec[0]=1;
2441                                         upvec[1]=0;
2442                                         upvec[2]=0;
2443                                         mul_m3_v3(mat, upvec);
2444
2445                                         /*make sure we have some z rolling*/
2446                                         if (fabs(upvec[2]) > 0.00001f) {
2447                                                 roll= upvec[2]*5;
2448                                                 upvec[0]=0; /*rotate the view about this axis*/
2449                                                 upvec[1]=0;
2450                                                 upvec[2]=1;
2451
2452                                                 mul_m3_v3(mat, upvec);
2453                                                 axis_angle_to_quat( tmp_quat, upvec, roll*time_redraw_clamped*fly->zlock_momentum * FLY_ZUP_CORRECT_FAC); /* Rotate about the relative up vec */
2454                                                 mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, tmp_quat);
2455
2456                                                 fly->zlock_momentum += FLY_ZUP_CORRECT_ACCEL;
2457                                         } else {
2458                                                 fly->zlock=1; /* dont check until the view rotates again */
2459                                                 fly->zlock_momentum= 0.0f;
2460                                         }
2461                                 }
2462
2463                                 if (fly->xlock==2 && moffset[1]==0) { /*only apply xcorrect when mouse isnt applying x rot*/
2464                                         upvec[0]=0;
2465                                         upvec[1]=0;
2466                                         upvec[2]=1;
2467                                         mul_m3_v3(mat, upvec);
2468                                         /*make sure we have some z rolling*/
2469                                         if (fabs(upvec[2]) > 0.00001) {
2470                                                 roll= upvec[2] * -5;
2471
2472                                                 upvec[0]= 1.0f; /*rotate the view about this axis*/
2473                                                 upvec[1]= 0.0f;
2474                                                 upvec[2]= 0.0f;
2475
2476                                                 mul_m3_v3(mat, upvec);
2477
2478                                                 axis_angle_to_quat( tmp_quat, upvec, roll*time_redraw_clamped*fly->xlock_momentum*0.1f); /* Rotate about the relative up vec */
2479                                                 mul_qt_qtqt(rv3d->viewquat, rv3d->viewquat, tmp_quat);
2480
2481                                                 fly->xlock_momentum += 0.05f;
2482                                         } else {
2483                                                 fly->xlock=1; /* see above */
2484                                                 fly->xlock_momentum= 0.0f;
2485                                         }
2486                                 }
2487
2488
2489                                 if (apply_rotation) {
2490                                         /* Normal operation */
2491                                         /* define dvec, view direction vector */
2492                                         dvec_tmp[0]= dvec_tmp[1]= dvec_tmp[2]= 0.0f;
2493                                         /* move along the current axis */
2494                                         dvec_tmp[fly->axis]= 1.0f;
2495
2496                                         mul_m3_v3(mat, dvec_tmp);
2497
2498                                         mul_v3_fl(dvec_tmp, fly->speed * time_redraw * 0.25f);
2499                                 }
2500                         }
2501
2502                         /* impose a directional lag */
2503                         interp_v3_v3v3(dvec, dvec_tmp, fly->dvec_prev, (1.0f/(1.0f+(time_redraw*5.0f))));
2504
2505                         if (rv3d->persp==RV3D_CAMOB) {
2506                                 Object *lock_ob= fly->root_parent ? fly->root_parent : fly->v3d->camera;
2507                                 if (lock_ob->protectflag & OB_LOCK_LOCX) dvec[0] = 0.0;
2508                                 if (lock_ob->protectflag & OB_LOCK_LOCY) dvec[1] = 0.0;
2509                                 if (lock_ob->protectflag & OB_LOCK_LOCZ) dvec[2] = 0.0;
2510                         }
2511
2512                         add_v3_v3(rv3d->ofs, dvec);
2513
2514                         /* todo, dynamic keys */
2515 #if 0
2516                         if (fly->zlock && fly->xlock)
2517                                 ED_area_headerprint(fly->ar, "FlyKeys  Speed:(+/- | Wheel),  Upright Axis:X  on/Z on,   Slow:Shift,  Direction:WASDRF,  Ok:LMB,  Pan:MMB,  Cancel:RMB");
2518                         else if (fly->zlock)
2519                                 ED_area_headerprint(fly->ar, "FlyKeys  Speed:(+/- | Wheel),  Upright Axis:X off/Z on,   Slow:Shift,  Direction:WASDRF,  Ok:LMB,  Pan:MMB,  Cancel:RMB");
2520                         else if (fly->xlock)
2521                                 ED_area_headerprint(fly->ar, "FlyKeys  Speed:(+/- | Wheel),  Upright Axis:X  on/Z off,  Slow:Shift,  Direction:WASDRF,  Ok:LMB,  Pan:MMB,  Cancel:RMB");
2522                         else
2523                                 ED_area_headerprint(fly->ar, "FlyKeys  Speed:(+/- | Wheel),  Upright Axis:X off/Z off,  Slow:Shift,  Direction:WASDRF,  Ok:LMB,  Pan:MMB,  Cancel:RMB");
2524 #endif
2525
2526                         /* we are in camera view so apply the view ofs and quat to the view matrix and set the camera to the view */
2527                         if (rv3d->persp==RV3D_CAMOB) {
2528                                 ID *id_key;
2529                                 /* transform the parent or the camera? */
2530                                 if(fly->root_parent) {
2531                                         Object *ob_update;
2532                     
2533                                         float view_mat[4][4];
2534                                         float prev_view_imat[4][4];
2535                                         float diff_mat[4][4];
2536                                         float parent_mat[4][4];
2537
2538                                         invert_m4_m4(prev_view_imat, prev_view_mat);
2539                                         view3d_persp_mat4(rv3d, view_mat);
2540                                         mul_m4_m4m4(diff_mat, prev_view_imat, view_mat);
2541                                         mul_m4_m4m4(parent_mat, fly->root_parent->obmat, diff_mat);
2542                                         object_apply_mat4(fly->root_parent, parent_mat);
2543
2544                                         // where_is_object(scene, fly->root_parent);
2545
2546                                         ob_update= v3d->camera->parent;
2547                                         while(ob_update) {
2548                                                 DAG_id_flush_update(&ob_update->id, OB_RECALC_OB);
2549                                                 ob_update= ob_update->parent;
2550                                         }
2551
2552                                         copy_m4_m4(prev_view_mat, view_mat);
2553
2554                                         id_key= &fly->root_parent->id;
2555
2556                                 }
2557                                 else {
2558                                         float view_mat[4][4];
2559                                         view3d_persp_mat4(rv3d, view_mat);
2560                                         object_apply_mat4(v3d->camera, view_mat);
2561                                         id_key= &v3d->camera->id;
2562                                 }
2563
2564                                 /* record the motion */
2565                                 if (autokeyframe_cfra_can_key(scene, id_key)) {
2566                                         ListBase dsources = {NULL, NULL};
2567                                         
2568                                         /* add datasource override for the camera object */
2569                                         ANIM_relative_keyingset_add_source(&dsources, id_key, NULL, NULL); 
2570                                         
2571                                         /* insert keyframes 
2572                                          *      1) on the first frame
2573                                          *      2) on each subsequent frame
2574                                          *              TODO: need to check in future that frame changed before doing this 
2575                                          */
2576                                         if (fly->xlock || fly->zlock || moffset[0] || moffset[1]) {
2577                                                 KeyingSet *ks= ANIM_builtin_keyingset_get_named(NULL, "Rotation");
2578                                                 ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA);
2579                                         }
2580                                         if (fly->speed) {
2581                                                 KeyingSet *ks= ANIM_builtin_keyingset_get_named(NULL, "Location");
2582                                                 ANIM_apply_keyingset(C, &dsources, NULL, ks, MODIFYKEY_MODE_INSERT, (float)CFRA);
2583                                         }
2584                                         
2585                                         /* free temp data */
2586                                         BLI_freelistN(&dsources);
2587                                 }
2588                         }
2589                 } else
2590                         /*were not redrawing but we need to update the time else the view will jump */
2591                         fly->time_lastdraw= PIL_check_seconds_timer();
2592                 /* end drawing */
2593                 VECCOPY(fly->dvec_prev, dvec);
2594         }
2595
2596 /* moved to flyEnd() */
2597
2598         return OPERATOR_FINISHED;
2599 }
2600
2601
2602
2603 static int fly_invoke(bContext *C, wmOperator *op, wmEvent *event)
2604 {
2605         RegionView3D *rv3d= CTX_wm_region_view3d(C);
2606         FlyInfo *fly;
2607
2608         if(rv3d->viewlock)
2609                 return OPERATOR_CANCELLED;
2610
2611         fly= MEM_callocN(sizeof(FlyInfo), "FlyOperation");
2612
2613         op->customdata= fly;
2614
2615         if(initFlyInfo(C, fly, op, event)==FALSE) {
2616                 MEM_freeN(op->customdata);
2617                 return OPERATOR_CANCELLED;
2618         }
2619
2620         flyEvent(fly, event);
2621
2622         WM_event_add_modal_handler(C, op);
2623
2624         return OPERATOR_RUNNING_MODAL;
2625 }
2626
2627 static int fly_cancel(bContext *C, wmOperator *op)
2628 {
2629         FlyInfo *fly = op->customdata;
2630
2631         fly->state = FLY_CANCEL;
2632         flyEnd(C, fly);
2633         op->customdata= NULL;
2634
2635         return OPERATOR_CANCELLED;
2636 }
2637
2638 static int fly_modal(bContext *C, wmOperator *op, wmEvent *event)
2639 {
2640         int exit_code;
2641
2642         FlyInfo *fly = op->customdata;
2643
2644         fly->redraw= 0;
2645
2646         flyEvent(fly, event);
2647
2648         if(event->type==TIMER && event->customdata == fly->timer)
2649                 flyApply(C, fly);
2650
2651         if(fly->redraw) {
2652                 ED_region_tag_redraw(CTX_wm_region(C));
2653         }
2654
2655         exit_code = flyEnd(C, fly);
2656
2657         if(exit_code!=OPERATOR_RUNNING_MODAL)
2658                 ED_region_tag_redraw(CTX_wm_region(C));
2659
2660         return exit_code;
2661 }
2662
2663 void VIEW3D_OT_fly(wmOperatorType *ot)
2664 {
2665
2666         /* identifiers */
2667         ot->name= "Fly Navigation";
2668         ot->description= "Interactively fly around the scene";
2669         ot->idname= "VIEW3D_OT_fly";
2670
2671         /* api callbacks */
2672         ot->invoke= fly_invoke;
2673         ot->cancel= fly_cancel;
2674         ot->modal= fly_modal;
2675         ot->poll= ED_operator_view3d_active;
2676
2677         /* flags */
2678         ot->flag= OPTYPE_BLOCKING;
2679
2680 }
2681
2682 /* ************************************** */
2683
2684 void view3d_align_axis_to_vector(View3D *v3d, RegionView3D *rv3d, int axisidx, float vec[3])
2685 {
2686         float alignaxis[3] = {0.0, 0.0, 0.0};
2687         float norm[3], axis[3], angle, new_quat[4];
2688         
2689         if(axisidx > 0) alignaxis[axisidx-1]= 1.0;
2690         else alignaxis[-axisidx-1]= -1.0;
2691
2692         normalize_v3_v3(norm, vec);
2693
2694         angle= (float)acos(dot_v3v3(alignaxis, norm));
2695         cross_v3_v3v3(axis, alignaxis, norm);
2696         axis_angle_to_quat( new_quat,axis, -angle);
2697         
2698         rv3d->view= 0;
2699         
2700         if (rv3d->persp==RV3D_CAMOB && v3d->camera) {
2701                 /* switch out of camera view */
2702                 float orig_ofs[3];
2703                 float orig_dist= rv3d->dist;
2704                 float orig_lens= v3d->lens;
2705                 
2706                 VECCOPY(orig_ofs, rv3d->ofs);
2707                 rv3d->persp= RV3D_PERSP;
2708                 rv3d->dist= 0.0;
2709                 view3d_settings_from_ob(v3d->camera, rv3d->ofs, NULL, NULL, &v3d->lens);
2710                 smooth_view(NULL, NULL, NULL, orig_ofs, new_quat, &orig_dist, &orig_lens); // XXX
2711         } else {
2712                 if (rv3d->persp==RV3D_CAMOB) rv3d->persp= RV3D_PERSP; /* switch out of camera mode */
2713                 smooth_view(NULL, NULL, NULL, NULL, new_quat, NULL, NULL); // XXX
2714         }
2715 }
2716