commit before doing some hefty shapekey change, will break compilation
[blender-staging.git] / source / blender / editors / space_view3d / view3d_view.c
1 /**
2  * $Id:
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. 
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * The Original Code is Copyright (C) 2008 Blender Foundation.
21  * All rights reserved.
22  *
23  * 
24  * Contributor(s): Blender Foundation
25  *
26  * ***** END GPL LICENSE BLOCK *****
27  */
28
29 #include <string.h>
30 #include <stdio.h>
31 #include <math.h>
32 #include <float.h>
33
34 #include "DNA_action_types.h"
35 #include "DNA_armature_types.h"
36 #include "DNA_camera_types.h"
37 #include "DNA_lamp_types.h"
38 #include "DNA_object_types.h"
39 #include "DNA_space_types.h"
40 #include "DNA_scene_types.h"
41 #include "DNA_screen_types.h"
42 #include "DNA_userdef_types.h"
43 #include "DNA_view3d_types.h"
44 #include "DNA_world_types.h"
45
46 #include "MEM_guardedalloc.h"
47
48 #include "BLI_arithb.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                 VecMulf(ofs, -1.0f); /*flip the vector*/
165         }
166         
167         /* Quat */
168         if (quat) {
169                 Mat4CpyMat4(bmat, ob->obmat);
170                 Mat4Ortho(bmat);
171                 Mat4Invert(imat, bmat);
172                 Mat3CpyMat4(tmat, imat);
173                 Mat3ToQuat(tmat, quat);
174         }
175         
176         if (dist) {
177                 float vec[3];
178                 Mat3CpyMat4(tmat, ob->obmat);
179                 
180                 vec[0]= vec[1] = 0.0;
181                 vec[2]= -(*dist);
182                 Mat3MulVecfl(tmat, vec);
183                 VecSubf(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(vec1);
267                                 Normalize(vec2);
268                                 /* scale the time allowed by the rotation */
269                                 sms.time_allowed *= NormalizedVecAngle2(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= V3D_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= V3D_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                 QuatInterpol(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         VecSubf(ob->loc, ob->loc, rv3d->ofs);
399         rv3d->viewquat[0]= -rv3d->viewquat[0];
400
401         QuatToEul(rv3d->viewquat, ob->rot);
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 = V3D_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= V3D_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 != V3D_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                 Mat4MulVec4fl(rv3d->persinv, vec);
497                 VecMulf(vec, 1.0f / vec[3]);
498                 
499                 VECCOPY(ray_start, rv3d->viewinv[3]);
500                 VECSUB(vec, vec, ray_start);
501                 Normalize(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                 Mat4MulVec4fl(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         VecSubf(ray_normal, ray_end, ray_start);
526         Normalize(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         Mat4MulMat4(vmat, ob->obmat, rv3d->viewmat);
605         Mat4MulMat4(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         VECCOPY(vec4, vec);
627         adr[0]= IS_CLIPPED;
628         vec4[3]= 1.0;
629         
630         Mat4MulVec4fl(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         Mat4MulMat4(mat, obmat, rv3d->persmat);
652         
653         for(a=0; a<8; a++) {
654                 VECCOPY(vec, bb->vec[a]);
655                 vec[3]= 1.0;
656                 Mat4MulVec4fl(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         Mat4MulVec4fl(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         Mat4MulVec4fl(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         Mat4MulVec4fl(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         Mat4MulVec4fl(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         Mat4MulVec4fl(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         Mat4MulVec4fl(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==V3D_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==V3D_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==V3D_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==V3D_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==V3D_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         Mat4CpyMat4(bmat, ob->obmat);
1005         Mat4Ortho(bmat);
1006         Mat4Invert(rv3d->viewmat, bmat);
1007         
1008         /* view quat calculation, needed for add object */
1009         Mat3CpyMat4(tmat, rv3d->viewmat);
1010         if (smooth) {
1011                 float new_quat[4];
1012                 if (rv3d->persp==V3D_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                         Mat3ToQuat(tmat, new_quat);
1022                         
1023                         rv3d->persp=V3D_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=V3D_CAMOB; /* just to be polite, not needed */
1030                         
1031                 } else {
1032                         Mat3ToQuat(tmat, new_quat);
1033                         smooth_view(NULL, NULL, NULL, NULL, new_quat, NULL, NULL); // XXX
1034                 }
1035         } else {
1036                 Mat3ToQuat(tmat, rv3d->viewquat);
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 V3D_VIEW_BOTTOM :
1046                 QUATSET(rv3d->viewquat,0.0, -1.0, 0.0, 0.0);
1047                 break;
1048                 
1049         case V3D_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 V3D_VIEW_LEFT:
1054                 QUATSET(rv3d->viewquat,0.5, -0.5, 0.5, 0.5);
1055                 break;
1056                 
1057         case V3D_VIEW_TOP:
1058                 QUATSET(rv3d->viewquat,1.0, 0.0, 0.0, 0.0);
1059                 break;
1060                 
1061         case V3D_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 V3D_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==V3D_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                         QuatToMat4(rv3d->viewquat, rv3d->viewmat);
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                 QuatToMat4(rv3d->viewquat, rv3d->viewmat);
1090                 if(rv3d->persp==V3D_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                                         Mat4MulVecfl(ob->obmat, vec);
1101                                 }
1102                         }
1103                         i_translate(-vec[0], -vec[1], -vec[2], rv3d->viewmat);
1104                 }
1105                 else i_translate(rv3d->ofs[0], rv3d->ofs[1], rv3d->ofs[2], rv3d->viewmat);
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         Mat4MulMat4(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                                                         Mat4CpyMat4(dob->ob->obmat, dob->mat);
1190                                                         
1191                                                         draw_object(scene, ar, v3d, &tbase, DRAW_PICKING|DRAW_CONSTCOLOR);
1192                                                         
1193                                                         Mat4CpyMat4(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         Mat4MulMat4(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==V3D_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==V3D_CAMOB) rv3d->persp= V3D_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) seperately 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, 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 static int game_engine_exec(bContext *C, wmOperator *unused)
1563 {
1564 #if GAMEBLENDER == 1
1565         Scene *startscene = CTX_data_scene(C);
1566         bScreen *sc= CTX_wm_screen(C);
1567         ScrArea *sa, *prevsa= CTX_wm_area(C);
1568         ARegion *ar, *prevar= CTX_wm_region(C);
1569
1570         sa= prevsa;
1571         if(sa->spacetype != SPACE_VIEW3D) {
1572                 for(sa=sc->areabase.first; sa; sa= sa->next)
1573                         if(sa->spacetype==SPACE_VIEW3D)
1574                                 break;
1575         }
1576
1577         if(!sa)
1578                 return OPERATOR_CANCELLED;
1579         
1580         for(ar=sa->regionbase.first; ar; ar=ar->next)
1581                 if(ar->regiontype == RGN_TYPE_WINDOW)
1582                         break;
1583         
1584         if(!ar)
1585                 return OPERATOR_CANCELLED;
1586         
1587         // bad context switch ..
1588         CTX_wm_area_set(C, sa);
1589         CTX_wm_region_set(C, ar);
1590
1591         view3d_operator_needs_opengl(C);
1592         
1593         game_set_commmandline_options(&startscene->gm);
1594
1595         SaveState(C);
1596         StartKetsjiShell(C, ar, 1);
1597         RestoreState(C);
1598         
1599         CTX_wm_region_set(C, prevar);
1600         CTX_wm_area_set(C, prevsa);
1601
1602         //XXX restore_all_scene_cfra(scene_cfra_store);
1603         set_scene_bg(startscene);
1604         //XXX scene_update_for_newframe(G.scene, G.scene->lay);
1605         
1606 #else
1607         printf("GameEngine Disabled\n");
1608 #endif
1609         ED_area_tag_redraw(CTX_wm_area(C));
1610         return OPERATOR_FINISHED;
1611 }
1612
1613 void VIEW3D_OT_game_start(wmOperatorType *ot)
1614 {
1615         
1616         /* identifiers */
1617         ot->name= "Start Game Engine";
1618         ot->description= "Start game engine.";
1619         ot->idname= "VIEW3D_OT_game_start";
1620         
1621         /* api callbacks */
1622         ot->exec= game_engine_exec;
1623         
1624         ot->poll= game_engine_poll;
1625 }
1626
1627
1628 /* NOTE: these defines are saved in keymap files, do not change values but just add new ones */
1629 #define FLY_MODAL_CANCEL                        1
1630 #define FLY_MODAL_CONFIRM                       2
1631 #define FLY_MODAL_ACCELERATE            3
1632 #define FLY_MODAL_DECELERATE            4
1633 #define FLY_MODAL_PAN_ENABLE            5
1634 #define FLY_MODAL_PAN_DISABLE           6
1635 #define FLY_MODAL_DIR_FORWARD           7
1636 #define FLY_MODAL_DIR_BACKWARD          8
1637 #define FLY_MODAL_DIR_LEFT                      9
1638 #define FLY_MODAL_DIR_RIGHT                     10
1639 #define FLY_MODAL_DIR_UP                        11
1640 #define FLY_MODAL_DIR_DOWN                      12
1641 #define FLY_MODAL_AXIS_LOCK_X           13
1642 #define FLY_MODAL_AXIS_LOCK_Z           14
1643 #define FLY_MODAL_PRECISION_ENABLE      15
1644 #define FLY_MODAL_PRECISION_DISABLE     16
1645
1646 /* called in transform_ops.c, on each regeneration of keymaps  */
1647 void fly_modal_keymap(wmKeyConfig *keyconf)
1648 {
1649         static EnumPropertyItem modal_items[] = {
1650         {FLY_MODAL_CANCEL,      "CANCEL", 0, "Cancel", ""},
1651         {FLY_MODAL_CONFIRM,     "CONFIRM", 0, "Confirm", ""},
1652         {FLY_MODAL_ACCELERATE, "ACCELERATE", 0, "Accelerate", ""},
1653         {FLY_MODAL_DECELERATE, "DECELERATE", 0, "Decelerate", ""},
1654
1655         {FLY_MODAL_PAN_ENABLE,  "PAN_ENABLE", 0, "Pan Enable", ""},
1656         {FLY_MODAL_PAN_DISABLE, "PAN_DISABLE", 0, "Pan Disable", ""},
1657
1658         {FLY_MODAL_DIR_FORWARD, "FORWARD", 0, "Fly Forward", ""},
1659         {FLY_MODAL_DIR_BACKWARD,"BACKWARD", 0, "Fly Backward", ""},
1660         {FLY_MODAL_DIR_LEFT,    "LEFT", 0, "Fly Left", ""},
1661         {FLY_MODAL_DIR_RIGHT,   "RIGHT", 0, "Fly Right", ""},
1662         {FLY_MODAL_DIR_UP,              "UP", 0, "Fly Up", ""},
1663         {FLY_MODAL_DIR_DOWN,    "DOWN", 0, "Fly Down", ""},
1664
1665         {FLY_MODAL_AXIS_LOCK_X, "AXIS_LOCK_X", 0, "X Axis Correction", "X axis correction (toggle)"},
1666         {FLY_MODAL_AXIS_LOCK_Z, "AXIS_LOCK_Z", 0, "X Axis Correction", "Z axis correction (toggle)"},
1667
1668         {FLY_MODAL_PRECISION_ENABLE,    "PRECISION_ENABLE", 0, "Precision Enable", ""},
1669         {FLY_MODAL_PRECISION_DISABLE,   "PRECISION_DISABLE", 0, "Precision Disable", ""},
1670
1671         {0, NULL, 0, NULL, NULL}};
1672
1673         wmKeyMap *keymap= WM_modalkeymap_get(keyconf, "View3D Fly Modal");
1674
1675         /* this function is called for each spacetype, only needs to add map once */
1676         if(keymap) return;
1677
1678         keymap= WM_modalkeymap_add(keyconf, "View3D Fly Modal", modal_items);
1679
1680         /* items for modal map */
1681         WM_modalkeymap_add_item(keymap, ESCKEY,    KM_PRESS, KM_ANY, 0, FLY_MODAL_CANCEL);
1682         WM_modalkeymap_add_item(keymap, RIGHTMOUSE, KM_ANY, KM_ANY, 0, FLY_MODAL_CANCEL);
1683
1684         WM_modalkeymap_add_item(keymap, LEFTMOUSE, KM_ANY, KM_ANY, 0, FLY_MODAL_CONFIRM);
1685         WM_modalkeymap_add_item(keymap, RETKEY, KM_PRESS, KM_ANY, 0, FLY_MODAL_CONFIRM);
1686         WM_modalkeymap_add_item(keymap, PADENTER, KM_PRESS, KM_ANY, 0, FLY_MODAL_CONFIRM);
1687
1688         WM_modalkeymap_add_item(keymap, PADPLUSKEY, KM_PRESS, 0, 0, FLY_MODAL_ACCELERATE);
1689         WM_modalkeymap_add_item(keymap, PADMINUS, KM_PRESS, 0, 0, FLY_MODAL_DECELERATE);
1690         WM_modalkeymap_add_item(keymap, WHEELUPMOUSE, KM_PRESS, 0, 0, FLY_MODAL_ACCELERATE);
1691         WM_modalkeymap_add_item(keymap, WHEELDOWNMOUSE, KM_PRESS, 0, 0, FLY_MODAL_DECELERATE);
1692
1693         WM_modalkeymap_add_item(keymap, MIDDLEMOUSE, KM_PRESS, KM_ANY, 0, FLY_MODAL_PAN_ENABLE);
1694         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 */
1695
1696         /* WASD */
1697         WM_modalkeymap_add_item(keymap, WKEY, KM_PRESS, 0, 0, FLY_MODAL_DIR_FORWARD);
1698         WM_modalkeymap_add_item(keymap, SKEY, KM_PRESS, 0, 0, FLY_MODAL_DIR_BACKWARD);
1699         WM_modalkeymap_add_item(keymap, AKEY, KM_PRESS, 0, 0, FLY_MODAL_DIR_LEFT);
1700         WM_modalkeymap_add_item(keymap, DKEY, KM_PRESS, 0, 0, FLY_MODAL_DIR_RIGHT);
1701         WM_modalkeymap_add_item(keymap, RKEY, KM_PRESS, 0, 0, FLY_MODAL_DIR_UP);
1702         WM_modalkeymap_add_item(keymap, FKEY, KM_PRESS, 0, 0, FLY_MODAL_DIR_DOWN);
1703
1704         WM_modalkeymap_add_item(keymap, XKEY, KM_PRESS, 0, 0, FLY_MODAL_AXIS_LOCK_X);
1705         WM_modalkeymap_add_item(keymap, ZKEY, KM_PRESS, 0, 0, FLY_MODAL_AXIS_LOCK_Z);
1706
1707         WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_PRESS, KM_ANY, 0, FLY_MODAL_PRECISION_ENABLE);
1708         WM_modalkeymap_add_item(keymap, LEFTSHIFTKEY, KM_RELEASE, KM_ANY, 0, FLY_MODAL_PRECISION_DISABLE);
1709
1710         /* assign map to operators */
1711         WM_modalkeymap_assign(keymap, "VIEW3D_OT_fly");
1712
1713 }
1714
1715 typedef struct FlyInfo {
1716         /* context stuff */
1717         RegionView3D *rv3d;
1718         View3D *v3d;
1719         ARegion *ar;
1720         Scene *scene;
1721
1722         wmTimer *timer; /* needed for redraws */
1723
1724         short state;
1725         short use_precision;
1726         short redraw;
1727         short mval[2];
1728
1729         /* fly state state */
1730         float speed; /* the speed the view is moving per redraw */
1731         short axis; /* Axis index to move allong by default Z to move allong the view */
1732         short pan_view; /* when true, pan the view instead of rotating */
1733
1734         /* relative view axis locking - xlock, zlock
1735         0; disabled
1736         1; enabled but not checking because mouse hasnt moved outside the margin since locking was checked an not needed
1737            when the mouse moves, locking is set to 2 so checks are done.
1738         2; mouse moved and checking needed, if no view altering is donem its changed back to 1 */
1739         short xlock, zlock;
1740         float xlock_momentum, zlock_momentum; /* nicer dynamics */
1741         float grid; /* world scale 1.0 default */
1742
1743         /* backup values */
1744         float dist_backup; /* backup the views distance since we use a zero dist for fly mode */
1745         float ofs_backup[3]; /* backup the views offset incase the user cancels flying in non camera mode */
1746         float rot_backup[4]; /* backup the views quat incase the user cancels flying in non camera mode. (quat for view, eul for camera) */
1747         short persp_backup; /* remember if were ortho or not, only used for restoring the view if it was a ortho view */
1748
1749         /* compare between last state */
1750         double time_lastwheel; /* used to accelerate when using the mousewheel a lot */
1751         double time_lastdraw; /* time between draws */
1752
1753         /* use for some lag */
1754         float dvec_prev[3]; /* old for some lag */
1755
1756 } FlyInfo;
1757
1758 /* FlyInfo->state */
1759 #define FLY_RUNNING             0
1760 #define FLY_CANCEL              1
1761 #define FLY_CONFIRM             2
1762
1763 int initFlyInfo (bContext *C, FlyInfo *fly, wmOperator *op, wmEvent *event)
1764 {
1765         float upvec[3]; // tmp
1766         float mat[3][3];
1767
1768         fly->rv3d= CTX_wm_region_view3d(C);
1769         fly->v3d = CTX_wm_view3d(C);
1770         fly->ar = CTX_wm_region(C);
1771         fly->scene= CTX_data_scene(C);
1772
1773         if(fly->rv3d->persp==V3D_CAMOB && fly->v3d->camera->id.lib) {
1774                 BKE_report(op->reports, RPT_ERROR, "Cannot fly a camera from an external library");
1775                 return FALSE;
1776         }
1777
1778         if(fly->v3d->ob_centre) {
1779                 BKE_report(op->reports, RPT_ERROR, "Cannot fly when the view is locked to an object");
1780                 return FALSE;
1781         }
1782
1783         if(fly->rv3d->persp==V3D_CAMOB && fly->v3d->camera->constraints.first) {
1784                 BKE_report(op->reports, RPT_ERROR, "Cannot fly an object with constraints");
1785                 return FALSE;
1786         }
1787
1788         fly->state= FLY_RUNNING;
1789         fly->speed= 0.0f;
1790         fly->axis= 2;
1791         fly->pan_view= FALSE;
1792         fly->xlock= FALSE;
1793         fly->zlock= TRUE;
1794         fly->xlock_momentum=0.0f;
1795         fly->zlock_momentum=0.0f;
1796         fly->grid= 1.0f;
1797         fly->use_precision= 0;
1798
1799         fly->dvec_prev[0]= fly->dvec_prev[1]= fly->dvec_prev[2]= 0.0f;
1800
1801         fly->timer= WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, 0.01f);
1802
1803
1804         /* we have to rely on events to give proper mousecoords after a warp_pointer */
1805 //XXX2.5        warp_pointer(cent_orig[0], cent_orig[1]);
1806         //fly->mval[0]= (fly->sa->winx)/2;
1807         //fly->mval[1]= (fly->sa->winy)/2;
1808
1809         fly->mval[0] = event->x - fly->ar->winrct.xmin;
1810         fly->mval[1] = event->y - fly->ar->winrct.ymin;
1811
1812
1813         fly->time_lastdraw= fly->time_lastwheel= PIL_check_seconds_timer();
1814
1815         fly->rv3d->rflag |= RV3D_FLYMODE; /* so we draw the corner margins */
1816
1817         /* detect weather to start with Z locking */
1818         upvec[0]=1.0f; upvec[1]=0.0f; upvec[2]=0.0f;
1819         Mat3CpyMat4(mat, fly->rv3d->viewinv);
1820         Mat3MulVecfl(mat, upvec);
1821         if (fabs(upvec[2]) < 0.1)
1822                 fly->zlock = 1;
1823         upvec[0]=0; upvec[1]=0; upvec[2]=0;
1824
1825         fly->persp_backup= fly->rv3d->persp;
1826         fly->dist_backup= fly->rv3d->dist;
1827         if (fly->rv3d->persp==V3D_CAMOB) {
1828                 /* store the origoinal camera loc and rot */
1829                 VECCOPY(fly->ofs_backup, fly->v3d->camera->loc);
1830                 VECCOPY(fly->rot_backup, fly->v3d->camera->rot);
1831
1832                 where_is_object(fly->scene, fly->v3d->camera);
1833                 VECCOPY(fly->rv3d->ofs, fly->v3d->camera->obmat[3]);
1834                 VecMulf(fly->rv3d->ofs, -1.0f); /*flip the vector*/
1835
1836                 fly->rv3d->dist=0.0;
1837                 fly->rv3d->viewbut=0;
1838
1839                 /* used for recording */
1840 //XXX2.5                if(v3d->camera->ipoflag & OB_ACTION_OB)
1841 //XXX2.5                        actname= "Object";
1842
1843         } else {
1844                 /* perspective or ortho */
1845                 if (fly->rv3d->persp==V3D_ORTHO)
1846                         fly->rv3d->persp= V3D_PERSP; /*if ortho projection, make perspective */
1847                 QUATCOPY(fly->rot_backup, fly->rv3d->viewquat);
1848                 VECCOPY(fly->ofs_backup, fly->rv3d->ofs);
1849                 fly->rv3d->dist= 0.0;
1850
1851                 upvec[2]= fly->dist_backup; /*x and y are 0*/
1852                 Mat3MulVecfl(mat, upvec);
1853                 VecSubf(fly->rv3d->ofs, fly->rv3d->ofs, upvec);
1854                 /*Done with correcting for the dist*/
1855         }
1856
1857         return 1;
1858 }
1859
1860 static int flyEnd(bContext *C, FlyInfo *fly)
1861 {
1862         RegionView3D *rv3d= fly->rv3d;
1863         View3D *v3d = fly->v3d;
1864
1865         float upvec[3];
1866
1867         if(fly->state == FLY_RUNNING)
1868                 return OPERATOR_RUNNING_MODAL;
1869
1870         WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), fly->timer);
1871
1872         rv3d->dist= fly->dist_backup;
1873
1874         if (fly->state == FLY_CANCEL) {
1875         /* Revert to original view? */
1876                 if (fly->persp_backup==V3D_CAMOB) { /* a camera view */
1877                         rv3d->viewbut=1;
1878                         VECCOPY(v3d->camera->loc, fly->ofs_backup);
1879                         VECCOPY(v3d->camera->rot, fly->rot_backup);
1880                         DAG_id_flush_update(&v3d->camera->id, OB_RECALC_OB);
1881                 } else {
1882                         /* Non Camera we need to reset the view back to the original location bacause the user canceled*/
1883                         QUATCOPY(rv3d->viewquat, fly->rot_backup);
1884                         VECCOPY(rv3d->ofs, fly->ofs_backup);
1885                         rv3d->persp= fly->persp_backup;
1886                 }
1887         }
1888         else if (fly->persp_backup==V3D_CAMOB) {        /* camera */
1889                 float mat3[3][3];
1890                 Mat3CpyMat4(mat3, v3d->camera->obmat);
1891                 Mat3ToCompatibleEul(mat3, v3d->camera->rot, fly->rot_backup);
1892
1893                 DAG_id_flush_update(&v3d->camera->id, OB_RECALC_OB);
1894 #if 0 //XXX2.5
1895                 if (IS_AUTOKEY_MODE(NORMAL)) {
1896                         allqueue(REDRAWIPO, 0);
1897                         allspace(REMAKEIPO, 0);
1898                         allqueue(REDRAWNLA, 0);
1899                         allqueue(REDRAWTIME, 0);
1900                 }
1901 #endif
1902         }
1903         else { /* not camera */
1904                 /* Apply the fly mode view */
1905                 /*restore the dist*/
1906                 float mat[3][3];
1907                 upvec[0]= upvec[1]= 0;
1908                 upvec[2]= fly->dist_backup; /*x and y are 0*/
1909                 Mat3CpyMat4(mat, rv3d->viewinv);
1910                 Mat3MulVecfl(mat, upvec);
1911                 VecAddf(rv3d->ofs, rv3d->ofs, upvec);
1912                 /*Done with correcting for the dist */
1913         }
1914
1915         rv3d->rflag &= ~RV3D_FLYMODE;
1916 //XXX2.5        BIF_view3d_previewrender_signal(fly->sa, PR_DBASE|PR_DISPRECT); /* not working at the moment not sure why */
1917
1918
1919         if(fly->state == FLY_CONFIRM) {
1920                 MEM_freeN(fly);
1921                 return OPERATOR_FINISHED;
1922         }
1923
1924         MEM_freeN(fly);
1925         return OPERATOR_CANCELLED;
1926 }
1927
1928 void flyEvent(FlyInfo *fly, wmEvent *event)
1929 {
1930         if (event->type == TIMER) {
1931                 fly->redraw = 1;
1932         }
1933         else if (event->type == MOUSEMOVE) {
1934                 fly->mval[0] = event->x - fly->ar->winrct.xmin;
1935                 fly->mval[1] = event->y - fly->ar->winrct.ymin;
1936         } /* handle modal keymap first */
1937         else if (event->type == EVT_MODAL_MAP) {
1938                 switch (event->val) {
1939                         case FLY_MODAL_CANCEL:
1940                                 fly->state = FLY_CANCEL;
1941                                 break;
1942                         case FLY_MODAL_CONFIRM:
1943                                 fly->state = FLY_CONFIRM;
1944                                 break;
1945
1946                         case FLY_MODAL_ACCELERATE:
1947                         {
1948                                 double time_currwheel;
1949                                 float time_wheel;
1950
1951                                 time_currwheel= PIL_check_seconds_timer();
1952                                 time_wheel = (float)(time_currwheel - fly->time_lastwheel);
1953                                 fly->time_lastwheel = time_currwheel;
1954                                 /*printf("Wheel %f\n", time_wheel);*/
1955                                 /*Mouse wheel delays range from 0.5==slow to 0.01==fast*/
1956                                 time_wheel = 1+ (10 - (20*MIN2(time_wheel, 0.5))); /* 0-0.5 -> 0-5.0 */
1957
1958                                 if (fly->speed<0.0f) fly->speed= 0.0f;
1959                                 else {
1960                                         if (event->shift)
1961                                                 fly->speed+= fly->grid*time_wheel*0.1;
1962                                         else
1963                                                 fly->speed+= fly->grid*time_wheel;
1964                                 }
1965                                 break;
1966                         }
1967                         case FLY_MODAL_DECELERATE:
1968                         {
1969                                 double time_currwheel;
1970                                 float time_wheel;
1971
1972                                 time_currwheel= PIL_check_seconds_timer();
1973                                 time_wheel = (float)(time_currwheel - fly->time_lastwheel);
1974                                 fly->time_lastwheel = time_currwheel;
1975                                 time_wheel = 1+ (10 - (20*MIN2(time_wheel, 0.5))); /* 0-0.5 -> 0-5.0 */
1976
1977                                 if (fly->speed>0) fly->speed=0;
1978                                 else {
1979                                         if (event->shift)
1980                                                 fly->speed-= fly->grid*time_wheel*0.1;
1981                                         else
1982                                                 fly->speed-= fly->grid*time_wheel;
1983                                 }
1984                                 break;
1985                         }
1986                         case FLY_MODAL_PAN_ENABLE:
1987                                 fly->pan_view= TRUE;
1988                                 break;
1989                         case FLY_MODAL_PAN_DISABLE:
1990 //XXX2.5                warp_pointer(cent_orig[0], cent_orig[1]);
1991                                 fly->pan_view= FALSE;
1992                                 break;
1993
1994                                 /* impliment WASD keys */
1995                         case FLY_MODAL_DIR_FORWARD:
1996                                 if (fly->speed < 0.0f) fly->speed= -fly->speed; /* flip speed rather then stopping, game like motion */
1997                                 else fly->speed += fly->grid; /* increse like mousewheel if were alredy moving in that difection*/
1998                                 fly->axis= 2;
1999                                 break;
2000                         case FLY_MODAL_DIR_BACKWARD:
2001                                 if (fly->speed>0) fly->speed= -fly->speed;
2002                                 else fly->speed -= fly->grid;
2003                                 fly->axis= 2;
2004                                 break;
2005                         case FLY_MODAL_DIR_LEFT:
2006                                 if (fly->speed < 0.0f) fly->speed= -fly->speed;
2007                                 fly->axis= 0;
2008                                 break;
2009                         case FLY_MODAL_DIR_RIGHT:
2010                                 if (fly->speed > 0.0f) fly->speed= -fly->speed;
2011                                 fly->axis= 0;
2012                                 break;
2013
2014                         case FLY_MODAL_DIR_UP:
2015                                 if (fly->speed < 0.0f) fly->speed= -fly->speed;
2016                                 fly->axis= 1;
2017                                 break;
2018
2019                         case FLY_MODAL_DIR_DOWN:
2020                                 if (fly->speed > 0.0f) fly->speed= -fly->speed;
2021                                 fly->axis= 1;
2022                                 break;
2023
2024                         case FLY_MODAL_AXIS_LOCK_X:
2025                                 if (fly->xlock) fly->xlock=0;
2026                                 else {
2027                                         fly->xlock = 2;
2028                                         fly->xlock_momentum = 0.0;
2029                                 }
2030                                 break;
2031                         case FLY_MODAL_AXIS_LOCK_Z:
2032                                 if (fly->zlock) fly->zlock=0;
2033                                 else {
2034                                         fly->zlock = 2;
2035                                         fly->zlock_momentum = 0.0;
2036                                 }
2037                                 break;
2038
2039                         case FLY_MODAL_PRECISION_ENABLE:
2040                                 fly->use_precision= TRUE;
2041                                 break;
2042                         case FLY_MODAL_PRECISION_DISABLE:
2043                                 fly->use_precision= FALSE;
2044                                 break;
2045
2046                 }
2047         }
2048 }
2049
2050 //int fly_exec(bContext *C, wmOperator *op)
2051 int flyApply(FlyInfo *fly)
2052 {
2053         /*
2054         fly mode - Shift+F
2055         a fly loop where the user can move move the view as if they are flying
2056         */
2057         RegionView3D *rv3d= fly->rv3d;
2058         View3D *v3d = fly->v3d;
2059         ARegion *ar = fly->ar;
2060         Scene *scene= fly->scene;
2061
2062         float mat[3][3], /* 3x3 copy of the view matrix so we can move allong the view axis */
2063         dvec[3]={0,0,0}, /* this is the direction thast added to the view offset per redraw */
2064
2065         /* Camera Uprighting variables */
2066         upvec[3]={0,0,0}, /* stores the view's up vector */
2067
2068         moffset[2], /* mouse offset from the views center */
2069         tmp_quat[4]; /* used for rotating the view */
2070
2071         int cent_orig[2], /* view center */
2072 //XXX- can avoid using //       cent[2], /* view center modified */
2073         xmargin, ymargin; /* x and y margin are define the safe area where the mouses movement wont rotate the view */
2074         unsigned char
2075         apply_rotation= 1; /* if the user presses shift they can look about without movinf the direction there looking*/
2076
2077         /* for recording */
2078 #if 0 //XXX2.5 todo, get animation recording working again.
2079         int playing_anim = 0; //XXX has_screenhandler(G.curscreen, SCREEN_HANDLER_ANIM);
2080         int cfra = -1; /*so the first frame always has a key added */
2081         char *actname="";
2082 #endif
2083         /* the dist defines a vector that is infront of the offset
2084         to rotate the view about.
2085         this is no good for fly mode because we
2086         want to rotate about the viewers center.
2087         but to correct the dist removal we must
2088         alter offset so the view doesn't jump. */
2089
2090         xmargin= ar->winx/20.0f;
2091         ymargin= ar->winy/20.0f;
2092
2093         cent_orig[0]= ar->winrct.xmin + ar->winx/2;
2094         cent_orig[1]= ar->winrct.ymin + ar->winy/2;
2095
2096         {
2097
2098                 /* mouse offset from the center */
2099                 moffset[0]= fly->mval[0]- ar->winx/2;
2100                 moffset[1]= fly->mval[1]- ar->winy/2;
2101
2102                 /* enforce a view margin */
2103                 if (moffset[0]>xmargin)                 moffset[0]-=xmargin;
2104                 else if (moffset[0] < -xmargin) moffset[0]+=xmargin;
2105                 else                                                    moffset[0]=0;
2106
2107                 if (moffset[1]>ymargin)                 moffset[1]-=ymargin;
2108                 else if (moffset[1] < -ymargin) moffset[1]+=ymargin;
2109                 else                                                    moffset[1]=0;
2110
2111
2112                 /* scale the mouse movement by this value - scales mouse movement to the view size
2113                  * moffset[0]/(ar->winx-xmargin*2) - window size minus margin (same for y)
2114                  *
2115                  * the mouse moves isnt linear */
2116
2117                 if(moffset[0]) {
2118                         moffset[0] /= ar->winx - (xmargin*2);
2119                         moffset[0] *= fabs(moffset[0]);
2120                 }
2121
2122                 if(moffset[1]) {
2123                         moffset[1] /= ar->winy - (ymargin*2);
2124                         moffset[1] *= fabs(moffset[1]);
2125                 }
2126
2127                 /* Should we redraw? */
2128                 if(fly->speed != 0.0f || moffset[0] || moffset[1] || fly->zlock || fly->xlock || dvec[0] || dvec[1] || dvec[2] ) {
2129                         float dvec_tmp[3];
2130                         double time_current, time_redraw; /*time how fast it takes for us to redraw, this is so simple scenes dont fly too fast */
2131                         float time_redraw_clamped;
2132
2133                         time_current= PIL_check_seconds_timer();
2134                         time_redraw= (float)(time_current - fly->time_lastdraw);
2135                         time_redraw_clamped= MIN2(0.05f, time_redraw); /* clamt the redraw time to avoid jitter in roll correction */
2136                         fly->time_lastdraw= time_current;
2137                         /*fprintf(stderr, "%f\n", time_redraw);*/ /* 0.002 is a small redraw 0.02 is larger */
2138
2139                         /* Scale the time to use shift to scale the speed down- just like
2140                         shift slows many other areas of blender down */
2141                         if (fly->use_precision)
2142                                 fly->speed= fly->speed * (1.0f-time_redraw_clamped);
2143
2144                         Mat3CpyMat4(mat, rv3d->viewinv);
2145
2146                         if (fly->pan_view==TRUE) {
2147                                 /* pan only */
2148                                 dvec_tmp[0]= -moffset[0];
2149                                 dvec_tmp[1]= -moffset[1];
2150                                 dvec_tmp[2]= 0;
2151
2152                                 if (fly->use_precision) {
2153                                         dvec_tmp[0] *= 0.1;
2154                                         dvec_tmp[1] *= 0.1;
2155                                 }
2156
2157                                 Mat3MulVecfl(mat, dvec_tmp);
2158                                 VecMulf(dvec_tmp, time_redraw*200.0 * fly->grid);
2159
2160                         } else {
2161                                 float roll; /* similar to the angle between the camera's up and the Z-up, but its very rough so just roll*/
2162
2163                                 /* rotate about the X axis- look up/down */
2164                                 if (moffset[1]) {
2165                                         upvec[0]=1;
2166                                         upvec[1]=0;
2167                                         upvec[2]=0;
2168                                         Mat3MulVecfl(mat, upvec);
2169                                         VecRotToQuat( upvec, (float)moffset[1]*-time_redraw*20, tmp_quat); /* Rotate about the relative up vec */
2170                                         QuatMul(rv3d->viewquat, rv3d->viewquat, tmp_quat);
2171
2172                                         if (fly->xlock) fly->xlock = 2; /*check for rotation*/
2173                                         if (fly->zlock) fly->zlock = 2;
2174                                         fly->xlock_momentum= 0.0f;
2175                                 }
2176
2177                                 /* rotate about the Y axis- look left/right */
2178                                 if (moffset[0]) {
2179
2180                                         /* if we're upside down invert the moffset */
2181                                         upvec[0]=0;
2182                                         upvec[1]=1;
2183                                         upvec[2]=0;
2184                                         Mat3MulVecfl(mat, upvec);
2185
2186                                         if(upvec[2] < 0.0f)
2187                                                 moffset[0]= -moffset[0];
2188
2189                                         /* make the lock vectors */
2190                                         if (fly->zlock) {
2191                                                 upvec[0]=0;
2192                                                 upvec[1]=0;
2193                                                 upvec[2]=1;
2194                                         } else {
2195                                                 upvec[0]=0;
2196                                                 upvec[1]=1;
2197                                                 upvec[2]=0;
2198                                                 Mat3MulVecfl(mat, upvec);
2199                                         }
2200
2201                                         VecRotToQuat( upvec, (float)moffset[0]*time_redraw*20, tmp_quat); /* Rotate about the relative up vec */
2202                                         QuatMul(rv3d->viewquat, rv3d->viewquat, tmp_quat);
2203
2204                                         if (fly->xlock) fly->xlock = 2;/*check for rotation*/
2205                                         if (fly->zlock) fly->zlock = 2;
2206                                 }
2207
2208                                 if (fly->zlock==2) {
2209                                         upvec[0]=1;
2210                                         upvec[1]=0;
2211                                         upvec[2]=0;
2212                                         Mat3MulVecfl(mat, upvec);
2213
2214                                         /*make sure we have some z rolling*/
2215                                         if (fabs(upvec[2]) > 0.00001f) {
2216                                                 roll= upvec[2]*5;
2217                                                 upvec[0]=0; /*rotate the view about this axis*/
2218                                                 upvec[1]=0;
2219                                                 upvec[2]=1;
2220
2221                                                 Mat3MulVecfl(mat, upvec);
2222                                                 VecRotToQuat( upvec, roll*time_redraw_clamped*fly->zlock_momentum*0.1, tmp_quat); /* Rotate about the relative up vec */
2223                                                 QuatMul(rv3d->viewquat, rv3d->viewquat, tmp_quat);
2224
2225                                                 fly->zlock_momentum += 0.05f;
2226                                         } else {
2227                                                 fly->zlock=1; /* dont check until the view rotates again */
2228                                                 fly->zlock_momentum= 0.0f;
2229                                         }
2230                                 }
2231
2232                                 if (fly->xlock==2 && moffset[1]==0) { /*only apply xcorrect when mouse isnt applying x rot*/
2233                                         upvec[0]=0;
2234                                         upvec[1]=0;
2235                                         upvec[2]=1;
2236                                         Mat3MulVecfl(mat, upvec);
2237                                         /*make sure we have some z rolling*/
2238                                         if (fabs(upvec[2]) > 0.00001) {
2239                                                 roll= upvec[2] * -5;
2240
2241                                                 upvec[0]= 1.0f; /*rotate the view about this axis*/
2242                                                 upvec[1]= 0.0f;
2243                                                 upvec[2]= 0.0f;
2244
2245                                                 Mat3MulVecfl(mat, upvec);
2246
2247                                                 VecRotToQuat( upvec, roll*time_redraw_clamped*fly->xlock_momentum*0.1f, tmp_quat); /* Rotate about the relative up vec */
2248                                                 QuatMul(rv3d->viewquat, rv3d->viewquat, tmp_quat);
2249
2250                                                 fly->xlock_momentum += 0.05f;
2251                                         } else {
2252                                                 fly->xlock=1; /* see above */
2253                                                 fly->xlock_momentum= 0.0f;
2254                                         }
2255                                 }
2256
2257
2258                                 if (apply_rotation) {
2259                                         /* Normal operation */
2260                                         /* define dvec, view direction vector */
2261                                         dvec_tmp[0]= dvec_tmp[1]= dvec_tmp[2]= 0.0f;
2262                                         /* move along the current axis */
2263                                         dvec_tmp[fly->axis]= 1.0f;
2264
2265                                         Mat3MulVecfl(mat, dvec_tmp);
2266
2267                                         VecMulf(dvec_tmp, fly->speed * time_redraw * 0.25f);
2268                                 }
2269                         }
2270
2271                         /* impose a directional lag */
2272                         VecLerpf(dvec, dvec_tmp, fly->dvec_prev, (1.0f/(1.0f+(time_redraw*5.0f))));
2273
2274                         if (rv3d->persp==V3D_CAMOB) {
2275                                 if (v3d->camera->protectflag & OB_LOCK_LOCX)
2276                                         dvec[0] = 0.0;
2277                                 if (v3d->camera->protectflag & OB_LOCK_LOCY)
2278                                         dvec[1] = 0.0;
2279                                 if (v3d->camera->protectflag & OB_LOCK_LOCZ)
2280                                         dvec[2] = 0.0;
2281                         }
2282
2283                         VecAddf(rv3d->ofs, rv3d->ofs, dvec);
2284 #if 0 //XXX2.5
2285                         if (fly->zlock && fly->xlock)
2286                                 headerprint("FlyKeys  Speed:(+/- | Wheel),  Upright Axis:X  on/Z on,   Slow:Shift,  Direction:WASDRF,  Ok:LMB,  Pan:MMB,  Cancel:RMB");
2287                         else if (fly->zlock)
2288                                 headerprint("FlyKeys  Speed:(+/- | Wheel),  Upright Axis:X off/Z on,   Slow:Shift,  Direction:WASDRF,  Ok:LMB,  Pan:MMB,  Cancel:RMB");
2289                         else if (fly->xlock)
2290                                 headerprint("FlyKeys  Speed:(+/- | Wheel),  Upright Axis:X  on/Z off,  Slow:Shift,  Direction:WASDRF,  Ok:LMB,  Pan:MMB,  Cancel:RMB");
2291                         else
2292                                 headerprint("FlyKeys  Speed:(+/- | Wheel),  Upright Axis:X off/Z off,  Slow:Shift,  Direction:WASDRF,  Ok:LMB,  Pan:MMB,  Cancel:RMB");
2293 #endif
2294
2295 //XXX2.5                        do_screenhandlers(G.curscreen); /* advance the next frame */
2296
2297                         /* we are in camera view so apply the view ofs and quat to the view matrix and set the camera to the view */
2298                         if (rv3d->persp==V3D_CAMOB) {
2299                                 rv3d->persp= V3D_PERSP; /*set this so setviewmatrixview3d uses the ofs and quat instead of the camera */
2300                                 setviewmatrixview3d(scene, v3d, rv3d);
2301
2302                                 setcameratoview3d(v3d, rv3d, v3d->camera);
2303
2304                                 {       //XXX - some reason setcameratoview3d doesnt copy, shouldnt not be needed!
2305                                         VECCOPY(v3d->camera->loc, rv3d->ofs);
2306                                         VecNegf(v3d->camera->loc);
2307                                 }
2308
2309                                 rv3d->persp= V3D_CAMOB;
2310 #if 0 //XXX2.5
2311                                 /* record the motion */
2312                                 if (IS_AUTOKEY_MODE(NORMAL) && (!playing_anim || cfra != G.scene->r.cfra)) {
2313                                         cfra = G.scene->r.cfra;
2314
2315                                         if (fly->xlock || fly->zlock || moffset[0] || moffset[1]) {
2316                                                 insertkey(&v3d->camera->id, ID_OB, actname, NULL, OB_ROT_X, 0);
2317                                                 insertkey(&v3d->camera->id, ID_OB, actname, NULL, OB_ROT_Y, 0);
2318                                                 insertkey(&v3d->camera->id, ID_OB, actname, NULL, OB_ROT_Z, 0);
2319                                         }
2320                                         if (fly->speed) {
2321                                                 insertkey(&v3d->camera->id, ID_OB, actname, NULL, OB_LOC_X, 0);
2322                                                 insertkey(&v3d->camera->id, ID_OB, actname, NULL, OB_LOC_Y, 0);
2323                                                 insertkey(&v3d->camera->id, ID_OB, actname, NULL, OB_LOC_Z, 0);
2324                                         }
2325                                 }
2326 #endif
2327                         }
2328 //XXX2.5                        scrarea_do_windraw(curarea);
2329 //XXX2.5                        screen_swapbuffers();
2330                 } else
2331                         /*were not redrawing but we need to update the time else the view will jump */
2332                         fly->time_lastdraw= PIL_check_seconds_timer();
2333                 /* end drawing */
2334                 VECCOPY(fly->dvec_prev, dvec);
2335         }
2336
2337 /* moved to flyEnd() */
2338
2339         return OPERATOR_FINISHED;
2340 }
2341
2342
2343
2344 static int fly_invoke(bContext *C, wmOperator *op, wmEvent *event)
2345 {
2346         RegionView3D *rv3d= CTX_wm_region_view3d(C);
2347         FlyInfo *fly;
2348
2349         if(rv3d->viewlock)
2350                 return OPERATOR_CANCELLED;
2351
2352         fly= MEM_callocN(sizeof(FlyInfo), "FlyOperation");
2353
2354         op->customdata= fly;
2355
2356         if(initFlyInfo(C, fly, op, event)==FALSE) {
2357                 MEM_freeN(op->customdata);
2358                 return OPERATOR_CANCELLED;
2359         }
2360
2361         flyEvent(fly, event);
2362
2363         WM_event_add_modal_handler(C, op);
2364
2365         return OPERATOR_RUNNING_MODAL;
2366 }
2367
2368 static int fly_cancel(bContext *C, wmOperator *op)
2369 {
2370         FlyInfo *fly = op->customdata;
2371
2372         fly->state = FLY_CANCEL;
2373         flyEnd(C, fly);
2374         op->customdata= NULL;
2375
2376         return OPERATOR_CANCELLED;
2377 }
2378
2379 static int fly_modal(bContext *C, wmOperator *op, wmEvent *event)
2380 {
2381         int exit_code;
2382
2383         FlyInfo *fly = op->customdata;
2384
2385         fly->redraw= 0;
2386
2387         flyEvent(fly, event);
2388
2389         if(event->type==TIMER)
2390                 flyApply(fly);
2391
2392         if(fly->redraw) {;
2393                 ED_region_tag_redraw(CTX_wm_region(C));
2394         }
2395
2396         exit_code = flyEnd(C, fly);
2397
2398         if(exit_code!=OPERATOR_RUNNING_MODAL)
2399                 ED_region_tag_redraw(CTX_wm_region(C));
2400
2401         return exit_code;
2402 }
2403
2404 void VIEW3D_OT_fly(wmOperatorType *ot)
2405 {
2406
2407         /* identifiers */
2408         ot->name= "Fly Navigation";
2409         ot->description= "Interactively fly around the scene.";
2410         ot->idname= "VIEW3D_OT_fly";
2411
2412         /* api callbacks */
2413         ot->invoke= fly_invoke;
2414         ot->cancel= fly_cancel;
2415         ot->modal= fly_modal;
2416         ot->poll= ED_operator_view3d_active;
2417
2418         /* flags */
2419         ot->flag= OPTYPE_BLOCKING;
2420
2421 }
2422
2423 /* ************************************** */
2424
2425 void view3d_align_axis_to_vector(View3D *v3d, RegionView3D *rv3d, int axisidx, float vec[3])
2426 {
2427         float alignaxis[3] = {0.0, 0.0, 0.0};
2428         float norm[3], axis[3], angle, new_quat[4];
2429         
2430         if(axisidx > 0) alignaxis[axisidx-1]= 1.0;
2431         else alignaxis[-axisidx-1]= -1.0;
2432         
2433         VECCOPY(norm, vec);
2434         Normalize(norm);
2435         
2436         angle= (float)acos(Inpf(alignaxis, norm));
2437         Crossf(axis, alignaxis, norm);
2438         VecRotToQuat(axis, -angle, new_quat);
2439         
2440         rv3d->view= 0;
2441         
2442         if (rv3d->persp==V3D_CAMOB && v3d->camera) {
2443                 /* switch out of camera view */
2444                 float orig_ofs[3];
2445                 float orig_dist= rv3d->dist;
2446                 float orig_lens= v3d->lens;
2447                 
2448                 VECCOPY(orig_ofs, rv3d->ofs);
2449                 rv3d->persp= V3D_PERSP;
2450                 rv3d->dist= 0.0;
2451                 view_settings_from_ob(v3d->camera, rv3d->ofs, NULL, NULL, &v3d->lens);
2452                 smooth_view(NULL, NULL, NULL, orig_ofs, new_quat, &orig_dist, &orig_lens); // XXX
2453         } else {
2454                 if (rv3d->persp==V3D_CAMOB) rv3d->persp= V3D_PERSP; /* switch out of camera mode */
2455                 smooth_view(NULL, NULL, NULL, NULL, new_quat, NULL, NULL); // XXX
2456         }
2457 }
2458