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