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