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