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