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