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