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