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