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