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