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