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