Camera tracking integration
[blender.git] / source / blender / editors / space_view3d / view3d_view.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version. 
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2008 Blender Foundation.
19  * All rights reserved.
20  *
21  * 
22  * Contributor(s): Blender Foundation
23  *
24  * ***** END GPL LICENSE BLOCK *****
25  */
26
27 /** \file blender/editors/space_view3d/view3d_view.c
28  *  \ingroup spview3d
29  */
30
31
32 #include "DNA_camera_types.h"
33 #include "DNA_scene_types.h"
34 #include "DNA_object_types.h"
35 #include "DNA_lamp_types.h"
36
37 #include "MEM_guardedalloc.h"
38
39 #include "BLI_math.h"
40 #include "BLI_rect.h"
41 #include "BLI_listbase.h"
42 #include "BLI_utildefines.h"
43
44 #include "BKE_anim.h"
45 #include "BKE_action.h"
46 #include "BKE_context.h"
47 #include "BKE_depsgraph.h"
48 #include "BKE_object.h"
49 #include "BKE_global.h"
50 #include "BKE_main.h"
51 #include "BKE_report.h"
52 #include "BKE_scene.h"
53 #include "BKE_screen.h"
54
55 #include "BIF_gl.h"
56 #include "BIF_glutil.h"
57
58 #include "GPU_draw.h"
59
60 #include "WM_api.h"
61 #include "WM_types.h"
62
63 #include "ED_screen.h"
64 #include "ED_armature.h"
65
66 #ifdef WITH_GAMEENGINE
67 #include "BL_System.h"
68 #endif
69
70 #include "view3d_intern.h"      // own include
71
72 /* use this call when executing an operator,
73    event system doesn't set for each event the
74    opengl drawing context */
75 void view3d_operator_needs_opengl(const bContext *C)
76 {
77         wmWindow *win = CTX_wm_window(C);
78         ARegion *ar= CTX_wm_region(C);
79         
80         view3d_region_operator_needs_opengl(win, ar);
81 }
82
83 void view3d_region_operator_needs_opengl(wmWindow *win, ARegion *ar)
84 {
85         /* for debugging purpose, context should always be OK */
86         if ((ar == NULL) || (ar->regiontype!=RGN_TYPE_WINDOW))
87                 printf("view3d_region_operator_needs_opengl error, wrong region\n");
88         else {
89                 RegionView3D *rv3d= ar->regiondata;
90                 
91                 wmSubWindowSet(win, ar->swinid);
92                 glMatrixMode(GL_PROJECTION);
93                 glLoadMatrixf(rv3d->winmat);
94                 glMatrixMode(GL_MODELVIEW);
95                 glLoadMatrixf(rv3d->viewmat);
96         }
97 }
98
99 float *give_cursor(Scene *scene, View3D *v3d)
100 {
101         if(v3d && v3d->localvd) return v3d->cursor;
102         else return scene->cursor;
103 }
104
105
106 /* Gets the lens and clipping values from a camera of lamp type object */
107 void ED_view3d_ob_clip_range_get(Object *ob, float *lens, float *clipsta, float *clipend)
108 {
109         if(ob->type==OB_LAMP ) {
110                 Lamp *la = ob->data;
111                 if (lens) {
112                         float x1, fac;
113                         fac= cosf((float)M_PI*la->spotsize/360.0f);
114                         x1= saacos(fac);
115                         *lens= 16.0f*fac/sinf(x1);
116                 }
117                 if (clipsta)    *clipsta= la->clipsta;
118                 if (clipend)    *clipend= la->clipend;
119         }
120         else if(ob->type==OB_CAMERA) {
121                 Camera *cam= ob->data;
122                 if (lens)               *lens= cam->lens;
123                 if (clipsta)    *clipsta= cam->clipsta;
124                 if (clipend)    *clipend= cam->clipend;
125         }
126         else {
127                 if (lens)               *lens= 35.0f;
128         }
129 }
130
131 /* ****************** smooth view operator ****************** */
132 /* This operator is one of the 'timer refresh' ones like animation playback */
133
134 struct SmoothViewStore {
135         float orig_dist, new_dist;
136         float orig_lens, new_lens;
137         float orig_quat[4], new_quat[4];
138         float orig_ofs[3], new_ofs[3];
139         
140         int to_camera, orig_view;
141         
142         double time_allowed;
143 };
144
145 /* will start timer if appropriate */
146 /* the arguments are the desired situation */
147 void smooth_view(bContext *C, View3D *v3d, ARegion *ar, Object *oldcamera, Object *camera, float *ofs, float *quat, float *dist, float *lens)
148 {
149         wmWindowManager *wm= CTX_wm_manager(C);
150         wmWindow *win= CTX_wm_window(C);
151         ScrArea *sa= CTX_wm_area(C);
152
153         RegionView3D *rv3d= ar->regiondata;
154         struct SmoothViewStore sms= {0};
155         short ok= FALSE;
156         
157         /* initialize sms */
158         copy_v3_v3(sms.new_ofs, rv3d->ofs);
159         copy_qt_qt(sms.new_quat, rv3d->viewquat);
160         sms.new_dist= rv3d->dist;
161         sms.new_lens= v3d->lens;
162         sms.to_camera= 0;
163
164         /* note on camera locking, this is a little confusing but works ok.
165          * we may be changing the view 'as if' there is no active camera, but infact
166          * there is an active camera which is locked to the view.
167          *
168          * In the case where smooth view is moving _to_ a camera we dont want that
169          * camera to be moved or changed, so only when the camera is not being set should
170          * we allow camera option locking to initialize the view settings from the camera.
171          */
172         if(camera == NULL && oldcamera == NULL) {
173                 ED_view3d_camera_lock_init(v3d, rv3d);
174         }
175
176         /* store the options we want to end with */
177         if(ofs) copy_v3_v3(sms.new_ofs, ofs);
178         if(quat) copy_qt_qt(sms.new_quat, quat);
179         if(dist) sms.new_dist= *dist;
180         if(lens) sms.new_lens= *lens;
181
182         if (camera) {
183                 ED_view3d_from_object(camera, sms.new_ofs, sms.new_quat, &sms.new_dist, &sms.new_lens);
184                 sms.to_camera= 1; /* restore view3d values in end */
185         }
186         
187         if (C && U.smooth_viewtx) {
188                 int changed = 0; /* zero means no difference */
189                 
190                 if (oldcamera != camera)
191                         changed = 1;
192                 else if (sms.new_dist != rv3d->dist)
193                         changed = 1;
194                 else if (sms.new_lens != v3d->lens)
195                         changed = 1;
196                 else if (!equals_v3v3(sms.new_ofs, rv3d->ofs))
197                         changed = 1;
198                 else if (!equals_v4v4(sms.new_quat, rv3d->viewquat))
199                         changed = 1;
200                 
201                 /* The new view is different from the old one
202                         * so animate the view */
203                 if (changed) {
204
205                         /* original values */
206                         if (oldcamera) {
207                                 sms.orig_dist= rv3d->dist; // below function does weird stuff with it...
208                                 ED_view3d_from_object(oldcamera, sms.orig_ofs, sms.orig_quat, &sms.orig_dist, &sms.orig_lens);
209                         }
210                         else {
211                                 copy_v3_v3(sms.orig_ofs, rv3d->ofs);
212                                 copy_qt_qt(sms.orig_quat, rv3d->viewquat);
213                                 sms.orig_dist= rv3d->dist;
214                                 sms.orig_lens= v3d->lens;
215                         }
216                         /* grid draw as floor */
217                         if((rv3d->viewlock & RV3D_LOCKED)==0) {
218                                 /* use existing if exists, means multiple calls to smooth view wont loose the original 'view' setting */
219                                 sms.orig_view= rv3d->sms ? rv3d->sms->orig_view : rv3d->view;
220                                 rv3d->view= RV3D_VIEW_USER;
221                         }
222
223                         sms.time_allowed= (double)U.smooth_viewtx / 1000.0;
224                         
225                         /* if this is view rotation only
226                                 * we can decrease the time allowed by
227                                 * the angle between quats 
228                                 * this means small rotations wont lag */
229                         if (quat && !ofs && !dist) {
230                                 float vec1[3]={0,0,1}, vec2[3]= {0,0,1};
231                                 float q1[4], q2[4];
232
233                                 invert_qt_qt(q1, sms.new_quat);
234                                 invert_qt_qt(q2, sms.orig_quat);
235
236                                 mul_qt_v3(q1, vec1);
237                                 mul_qt_v3(q2, vec2);
238
239                                 /* scale the time allowed by the rotation */
240                                 sms.time_allowed *= (double)angle_v3v3(vec1, vec2) / M_PI; /* 180deg == 1.0 */
241                         }
242
243                         /* ensure it shows correct */
244                         if(sms.to_camera) rv3d->persp= RV3D_PERSP;
245
246                         rv3d->rflag |= RV3D_NAVIGATING;
247                         
248                         /* keep track of running timer! */
249                         if(rv3d->sms==NULL)
250                                 rv3d->sms= MEM_mallocN(sizeof(struct SmoothViewStore), "smoothview v3d");
251                         *rv3d->sms= sms;
252                         if(rv3d->smooth_timer)
253                                 WM_event_remove_timer(wm, win, rv3d->smooth_timer);
254                         /* TIMER1 is hardcoded in keymap */
255                         rv3d->smooth_timer= WM_event_add_timer(wm, win, TIMER1, 1.0/100.0);     /* max 30 frs/sec */
256                         
257                         ok= TRUE;
258                 }
259         }
260         
261         /* if we get here nothing happens */
262         if(ok == FALSE) {
263                 if(sms.to_camera==0) {
264                         copy_v3_v3(rv3d->ofs, sms.new_ofs);
265                         copy_qt_qt(rv3d->viewquat, sms.new_quat);
266                         rv3d->dist = sms.new_dist;
267                         v3d->lens = sms.new_lens;
268                 }
269
270                 if(rv3d->viewlock & RV3D_BOXVIEW)
271                         view3d_boxview_copy(sa, ar);
272
273                 ED_region_tag_redraw(ar);
274         }
275 }
276
277 /* only meant for timer usage */
278 static int view3d_smoothview_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *event)
279 {
280         View3D *v3d = CTX_wm_view3d(C);
281         RegionView3D *rv3d= CTX_wm_region_view3d(C);
282         struct SmoothViewStore *sms= rv3d->sms;
283         float step, step_inv;
284         
285         /* escape if not our timer */
286         if(rv3d->smooth_timer==NULL || rv3d->smooth_timer!=event->customdata)
287                 return OPERATOR_PASS_THROUGH;
288         
289         if(sms->time_allowed != 0.0)
290                 step = (float)((rv3d->smooth_timer->duration)/sms->time_allowed);
291         else
292                 step = 1.0f;
293         
294         /* end timer */
295         if(step >= 1.0f) {
296                 
297                 /* if we went to camera, store the original */
298                 if(sms->to_camera) {
299                         rv3d->persp= RV3D_CAMOB;
300                         copy_v3_v3(rv3d->ofs, sms->orig_ofs);
301                         copy_qt_qt(rv3d->viewquat, sms->orig_quat);
302                         rv3d->dist = sms->orig_dist;
303                         v3d->lens = sms->orig_lens;
304                 }
305                 else {
306                         copy_v3_v3(rv3d->ofs, sms->new_ofs);
307                         copy_qt_qt(rv3d->viewquat, sms->new_quat);
308                         rv3d->dist = sms->new_dist;
309                         v3d->lens = sms->new_lens;
310
311                         ED_view3d_camera_lock_sync(v3d, rv3d);
312                 }
313                 
314                 if((rv3d->viewlock & RV3D_LOCKED)==0) {
315                         rv3d->view= sms->orig_view;
316                 }
317
318                 MEM_freeN(rv3d->sms);
319                 rv3d->sms= NULL;
320                 
321                 WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), rv3d->smooth_timer);
322                 rv3d->smooth_timer= NULL;
323                 rv3d->rflag &= ~RV3D_NAVIGATING;
324         }
325         else {
326                 int i;
327                 
328                 /* ease in/out */
329                 if (step < 0.5f)        step = (float)pow(step*2.0f, 2.0)/2.0f;
330                 else                            step = (float)1.0f-(powf(2.0f*(1.0f-step),2.0f)/2.0f);
331
332                 step_inv = 1.0f-step;
333
334                 for (i=0; i<3; i++)
335                         rv3d->ofs[i] = sms->new_ofs[i] * step + sms->orig_ofs[i]*step_inv;
336
337                 interp_qt_qtqt(rv3d->viewquat, sms->orig_quat, sms->new_quat, step);
338                 
339                 rv3d->dist = sms->new_dist * step + sms->orig_dist*step_inv;
340                 v3d->lens = sms->new_lens * step + sms->orig_lens*step_inv;
341
342                 ED_view3d_camera_lock_sync(v3d, rv3d);
343         }
344         
345         if(rv3d->viewlock & RV3D_BOXVIEW)
346                 view3d_boxview_copy(CTX_wm_area(C), CTX_wm_region(C));
347         
348         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, v3d);
349         
350         return OPERATOR_FINISHED;
351 }
352
353 void VIEW3D_OT_smoothview(wmOperatorType *ot)
354 {
355         
356         /* identifiers */
357         ot->name= "Smooth View";
358         ot->idname= "VIEW3D_OT_smoothview";
359         ot->description="The time to animate the change of view (in milliseconds)";
360         
361         /* api callbacks */
362         ot->invoke= view3d_smoothview_invoke;
363         
364         ot->poll= ED_operator_view3d_active;
365 }
366
367 /* ****************** change view operators ****************** */
368
369 static int view3d_setcameratoview_exec(bContext *C, wmOperator *UNUSED(op))
370 {
371         View3D *v3d = CTX_wm_view3d(C);
372         RegionView3D *rv3d= CTX_wm_region_view3d(C);
373
374         copy_qt_qt(rv3d->lviewquat, rv3d->viewquat);
375         rv3d->lview= rv3d->view;
376         if(rv3d->persp != RV3D_CAMOB) {
377                 rv3d->lpersp= rv3d->persp;
378         }
379
380         ED_view3d_to_object(v3d->camera, rv3d->ofs, rv3d->viewquat, rv3d->dist);
381         DAG_id_tag_update(&v3d->camera->id, OB_RECALC_OB);
382         rv3d->persp = RV3D_CAMOB;
383         
384         WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, v3d->camera);
385         
386         return OPERATOR_FINISHED;
387
388 }
389
390 static int view3d_setcameratoview_poll(bContext *C)
391 {
392         View3D *v3d= CTX_wm_view3d(C);
393         if(v3d && v3d->camera && v3d->camera->id.lib==NULL) {
394                 RegionView3D *rv3d= CTX_wm_region_view3d(C);
395                 if(rv3d && !rv3d->viewlock) {
396                         return 1;
397                 }
398         }
399
400         return 0;
401 }
402
403 void VIEW3D_OT_setcameratoview(wmOperatorType *ot)
404 {
405         
406         /* identifiers */
407         ot->name= "Align Camera To View";
408         ot->description= "Set camera view to active view";
409         ot->idname= "VIEW3D_OT_camera_to_view";
410         
411         /* api callbacks */
412         ot->exec= view3d_setcameratoview_exec;  
413         ot->poll= view3d_setcameratoview_poll;
414         
415         /* flags */
416         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
417 }
418
419
420 static int view3d_setobjectascamera_exec(bContext *C, wmOperator *UNUSED(op))
421 {
422         View3D *v3d = CTX_wm_view3d(C);
423         ARegion *ar= ED_view3d_context_region_unlock(C);
424         RegionView3D *rv3d= ar->regiondata; /* no NULL check is needed, poll checks */
425         Scene *scene= CTX_data_scene(C);
426         Object *ob = CTX_data_active_object(C);
427
428         if(ob) {
429                 Object *camera_old= (rv3d->persp == RV3D_CAMOB) ? V3D_CAMERA_SCENE(scene, v3d) : NULL;
430                 rv3d->persp= RV3D_CAMOB;
431                 v3d->camera= ob;
432                 if(v3d->scenelock)
433                         scene->camera= ob;
434
435                 if(camera_old != ob) /* unlikely but looks like a glitch when set to the same */
436                         smooth_view(C, v3d, ar, camera_old, v3d->camera, rv3d->ofs, rv3d->viewquat, &rv3d->dist, &v3d->lens);
437
438                 WM_event_add_notifier(C, NC_SCENE|ND_RENDER_OPTIONS|NC_OBJECT|ND_DRAW, CTX_data_scene(C));
439         }
440         
441         return OPERATOR_FINISHED;
442 }
443
444 int ED_operator_rv3d_unlock_poll(bContext *C)
445 {
446         return ED_view3d_context_region_unlock(C) != NULL;
447 }
448
449 void VIEW3D_OT_object_as_camera(wmOperatorType *ot)
450 {
451         
452         /* identifiers */
453         ot->name= "Set Active Object as Camera";
454         ot->description= "Set the active object as the active camera for this view or scene";
455         ot->idname= "VIEW3D_OT_object_as_camera";
456         
457         /* api callbacks */
458         ot->exec= view3d_setobjectascamera_exec;        
459         ot->poll= ED_operator_rv3d_unlock_poll;
460         
461         /* flags */
462         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
463 }
464
465 /* ********************************** */
466
467 void ED_view3d_calc_clipping(BoundBox *bb, float planes[4][4], bglMats *mats, rcti *rect)
468 {
469         float modelview[4][4];
470         double xs, ys, p[3];
471         int val, flip_sign, a;
472
473         /* near zero floating point values can give issues with gluUnProject
474                 in side view on some implementations */
475         if(fabs(mats->modelview[0]) < 1e-6) mats->modelview[0]= 0.0;
476         if(fabs(mats->modelview[5]) < 1e-6) mats->modelview[5]= 0.0;
477
478         /* Set up viewport so that gluUnProject will give correct values */
479         mats->viewport[0] = 0;
480         mats->viewport[1] = 0;
481
482         /* four clipping planes and bounding volume */
483         /* first do the bounding volume */
484         for(val=0; val<4; val++) {
485                 xs= (val==0||val==3)?rect->xmin:rect->xmax;
486                 ys= (val==0||val==1)?rect->ymin:rect->ymax;
487
488                 gluUnProject(xs, ys, 0.0, mats->modelview, mats->projection, mats->viewport, &p[0], &p[1], &p[2]);
489                 VECCOPY(bb->vec[val], p);
490
491                 gluUnProject(xs, ys, 1.0, mats->modelview, mats->projection, mats->viewport, &p[0], &p[1], &p[2]);
492                 VECCOPY(bb->vec[4+val], p);
493         }
494
495         /* verify if we have negative scale. doing the transform before cross
496            product flips the sign of the vector compared to doing cross product
497            before transform then, so we correct for that. */
498         for(a=0; a<16; a++)
499                 ((float*)modelview)[a] = mats->modelview[a];
500         flip_sign = is_negative_m4(modelview);
501
502         /* then plane equations */
503         for(val=0; val<4; val++) {
504
505                 normal_tri_v3(planes[val], bb->vec[val], bb->vec[val==3?0:val+1], bb->vec[val+4]);
506
507                 if(flip_sign)
508                         negate_v3(planes[val]);
509
510                 planes[val][3]= - planes[val][0]*bb->vec[val][0]
511                         - planes[val][1]*bb->vec[val][1]
512                         - planes[val][2]*bb->vec[val][2];
513         }
514 }
515
516 /* create intersection coordinates in view Z direction at mouse coordinates */
517 void ED_view3d_win_to_segment_clip(ARegion *ar, View3D *v3d, const float mval[2], float ray_start[3], float ray_end[3])
518 {
519         RegionView3D *rv3d= ar->regiondata;
520         
521         if(rv3d->is_persp) {
522                 float vec[3];
523                 ED_view3d_win_to_vector(ar, mval, vec);
524
525                 copy_v3_v3(ray_start, rv3d->viewinv[3]);
526                 madd_v3_v3v3fl(ray_start, rv3d->viewinv[3], vec, v3d->near);
527                 madd_v3_v3v3fl(ray_end, rv3d->viewinv[3], vec, v3d->far);
528         }
529         else {
530                 float vec[4];
531                 vec[0] = 2.0f * mval[0] / ar->winx - 1;
532                 vec[1] = 2.0f * mval[1] / ar->winy - 1;
533                 vec[2] = 0.0f;
534                 vec[3] = 1.0f;
535                 
536                 mul_m4_v4(rv3d->persinv, vec);
537                 
538                 madd_v3_v3v3fl(ray_start, vec, rv3d->viewinv[2],  1000.0f);
539                 madd_v3_v3v3fl(ray_end, vec, rv3d->viewinv[2], -1000.0f);
540         }
541
542         /* clipping */
543         if(rv3d->rflag & RV3D_CLIPPING) {
544                 int a;
545                 for(a=0; a<4; a++) {
546                         clip_line_plane(ray_start, ray_end, rv3d->clip[a]);
547                 }
548         }
549 }
550
551 /* create intersection ray in view Z direction at mouse coordinates */
552 void ED_view3d_win_to_ray(ARegion *ar, View3D *v3d, const float mval[2], float ray_start[3], float ray_normal[3])
553 {
554         float ray_end[3];
555         
556         ED_view3d_win_to_segment_clip(ar, v3d, mval, ray_start, ray_end);
557         sub_v3_v3v3(ray_normal, ray_end, ray_start);
558         normalize_v3(ray_normal);
559 }
560
561 void ED_view3d_global_to_vector(RegionView3D *rv3d, const float coord[3], float vec[3])
562 {
563         if (rv3d->is_persp) {
564                 float p1[4], p2[4];
565
566                 copy_v3_v3(p1, coord);
567                 p1[3] = 1.0f;
568                 copy_v3_v3(p2, p1);
569                 p2[3] = 1.0f;
570                 mul_m4_v4(rv3d->viewmat, p2);
571
572                 mul_v3_fl(p2, 2.0f);
573
574                 mul_m4_v4(rv3d->viewinv, p2);
575
576                 sub_v3_v3v3(vec, p1, p2);
577         }
578         else {
579                 copy_v3_v3(vec, rv3d->viewinv[2]);
580         }
581         normalize_v3(vec);
582 }
583
584 int initgrabz(RegionView3D *rv3d, float x, float y, float z)
585 {
586         int flip= FALSE;
587         if(rv3d==NULL) return flip;
588         rv3d->zfac= rv3d->persmat[0][3]*x+ rv3d->persmat[1][3]*y+ rv3d->persmat[2][3]*z+ rv3d->persmat[3][3];
589         if (rv3d->zfac < 0.0f)
590                 flip= TRUE;
591         /* if x,y,z is exactly the viewport offset, zfac is 0 and we don't want that 
592                 * (accounting for near zero values)
593                 * */
594         if (rv3d->zfac < 1.e-6f && rv3d->zfac > -1.e-6f) rv3d->zfac = 1.0f;
595         
596         /* Negative zfac means x, y, z was behind the camera (in perspective).
597                 * This gives flipped directions, so revert back to ok default case.
598         */
599         // NOTE: I've changed this to flip zfac to be positive again for now so that GPencil draws ok
600         //      -- Aligorith, 2009Aug31
601         //if (rv3d->zfac < 0.0f) rv3d->zfac = 1.0f;
602         if (rv3d->zfac < 0.0f) rv3d->zfac= -rv3d->zfac;
603         
604         return flip;
605 }
606
607 void ED_view3d_win_to_3d(ARegion *ar, const float depth_pt[3], const float mval[2], float out[3])
608 {
609         RegionView3D *rv3d= ar->regiondata;
610         
611         float line_sta[3];
612         float line_end[3];
613
614         if(rv3d->is_persp) {
615                 float mousevec[3];
616                 copy_v3_v3(line_sta, rv3d->viewinv[3]);
617                 ED_view3d_win_to_vector(ar, mval, mousevec);
618                 add_v3_v3v3(line_end, line_sta, mousevec);
619
620                 if(isect_line_plane_v3(out, line_sta, line_end, depth_pt, rv3d->viewinv[2], TRUE) == 0) {
621                         /* highly unlikely to ever happen, mouse vec paralelle with view plane */
622                         zero_v3(out);
623                 }
624         }
625         else {
626                 const float dx= (2.0f * mval[0] / (float)ar->winx) - 1.0f;
627                 const float dy= (2.0f * mval[1] / (float)ar->winy) - 1.0f;
628                 line_sta[0]= (rv3d->persinv[0][0] * dx) + (rv3d->persinv[1][0] * dy) + rv3d->viewinv[3][0];
629                 line_sta[1]= (rv3d->persinv[0][1] * dx) + (rv3d->persinv[1][1] * dy) + rv3d->viewinv[3][1];
630                 line_sta[2]= (rv3d->persinv[0][2] * dx) + (rv3d->persinv[1][2] * dy) + rv3d->viewinv[3][2];
631
632                 add_v3_v3v3(line_end, line_sta, rv3d->viewinv[2]);
633                 closest_to_line_v3(out, depth_pt, line_sta, line_end);
634         }
635 }
636
637 /* always call initgrabz */
638 /* only to detect delta motion */
639 void ED_view3d_win_to_delta(ARegion *ar, const float mval[2], float out[3])
640 {
641         RegionView3D *rv3d= ar->regiondata;
642         float dx, dy;
643         
644         dx= 2.0f*mval[0]*rv3d->zfac/ar->winx;
645         dy= 2.0f*mval[1]*rv3d->zfac/ar->winy;
646         
647         out[0]= (rv3d->persinv[0][0]*dx + rv3d->persinv[1][0]*dy);
648         out[1]= (rv3d->persinv[0][1]*dx + rv3d->persinv[1][1]*dy);
649         out[2]= (rv3d->persinv[0][2]*dx + rv3d->persinv[1][2]*dy);
650 }
651
652 /* doesn't rely on initgrabz */
653 /* for perspective view, get the vector direction to
654  * the mouse cursor as a normalized vector */
655 void ED_view3d_win_to_vector(ARegion *ar, const float mval[2], float out[3])
656 {
657         RegionView3D *rv3d= ar->regiondata;
658
659         if(rv3d->is_persp) {
660                 out[0]= 2.0f * (mval[0] / ar->winx) - 1.0f;
661                 out[1]= 2.0f * (mval[1] / ar->winy) - 1.0f;
662                 out[2]= -0.5f;
663                 mul_project_m4_v3(rv3d->persinv, out);
664                 sub_v3_v3(out, rv3d->viewinv[3]);
665         }
666         else {
667                 copy_v3_v3(out, rv3d->viewinv[2]);
668         }
669         normalize_v3(out);
670 }
671
672 float ED_view3d_depth_read_cached(ViewContext *vc, int x, int y)
673 {
674         ViewDepths *vd = vc->rv3d->depths;
675                 
676         x -= vc->ar->winrct.xmin;
677         y -= vc->ar->winrct.ymin;
678
679         if(vd && vd->depths && x > 0 && y > 0 && x < vd->w && y < vd->h)
680                 return vd->depths[y * vd->w + x];
681         else
682                 return 1;
683 }
684
685 void ED_view3d_depth_tag_update(RegionView3D *rv3d)
686 {
687         if(rv3d->depths)
688                 rv3d->depths->damaged= 1;
689 }
690
691 void ED_view3d_ob_project_mat_get(RegionView3D *rv3d, Object *ob, float pmat[4][4])
692 {
693         float vmat[4][4];
694         
695         mul_m4_m4m4(vmat, ob->obmat, rv3d->viewmat);
696         mul_m4_m4m4(pmat, vmat, rv3d->winmat);
697 }
698
699 #if 0
700 /* Uses window coordinates (x,y) and depth component z to find a point in
701    modelspace */
702 void view3d_unproject(bglMats *mats, float out[3], const short x, const short y, const float z)
703 {
704         double ux, uy, uz;
705
706                 gluUnProject(x,y,z, mats->modelview, mats->projection,
707                          (GLint *)mats->viewport, &ux, &uy, &uz );
708         out[0] = ux;
709         out[1] = uy;
710         out[2] = uz;
711 }
712 #endif
713
714 /* use view3d_get_object_project_mat to get projecting mat */
715 void ED_view3d_project_float(ARegion *ar, const float vec[3], float adr[2], float mat[4][4])
716 {
717         float vec4[4];
718         
719         adr[0]= IS_CLIPPED;
720         copy_v3_v3(vec4, vec);
721         vec4[3]= 1.0;
722         
723         mul_m4_v4(mat, vec4);
724         
725         if( vec4[3]>FLT_EPSILON ) {
726                 adr[0] = (float)(ar->winx/2.0f)+(ar->winx/2.0f)*vec4[0]/vec4[3];        
727                 adr[1] = (float)(ar->winy/2.0f)+(ar->winy/2.0f)*vec4[1]/vec4[3];
728         } else {
729                 adr[0] = adr[1] = 0.0f;
730         }
731 }
732
733 /* use view3d_get_object_project_mat to get projecting mat */
734 void ED_view3d_project_float_v3(ARegion *ar, float *vec, float *adr, float mat[4][4])
735 {
736         float vec4[4];
737         
738         copy_v3_v3(vec4, vec);
739         vec4[3]= 1.0;
740         adr[0]= IS_CLIPPED;
741         
742         mul_m4_v4(mat, vec4);
743         
744         if( vec4[3]>FLT_EPSILON ) {
745                 adr[0] = (float)(ar->winx/2.0f)+(ar->winx/2.0f)*vec4[0]/vec4[3];        
746                 adr[1] = (float)(ar->winy/2.0f)+(ar->winy/2.0f)*vec4[1]/vec4[3];
747                 adr[2] = vec4[2]/vec4[3];
748         } else {
749                 adr[0] = adr[1] = adr[2] = 0.0f;
750         }
751 }
752
753 int ED_view3d_boundbox_clip(RegionView3D *rv3d, float obmat[][4], BoundBox *bb)
754 {
755         /* return 1: draw */
756         
757         float mat[4][4];
758         float vec[4], min, max;
759         int a, flag= -1, fl;
760         
761         if(bb==NULL) return 1;
762         if(bb->flag & OB_BB_DISABLED) return 1;
763         
764         mul_m4_m4m4(mat, obmat, rv3d->persmat);
765         
766         for(a=0; a<8; a++) {
767                 copy_v3_v3(vec, bb->vec[a]);
768                 vec[3]= 1.0;
769                 mul_m4_v4(mat, vec);
770                 max= vec[3];
771                 min= -vec[3];
772                 
773                 fl= 0;
774                 if(vec[0] < min) fl+= 1;
775                 if(vec[0] > max) fl+= 2;
776                 if(vec[1] < min) fl+= 4;
777                 if(vec[1] > max) fl+= 8;
778                 if(vec[2] < min) fl+= 16;
779                 if(vec[2] > max) fl+= 32;
780                 
781                 flag &= fl;
782                 if(flag==0) return 1;
783         }
784         
785         return 0;
786 }
787
788 void project_short(ARegion *ar, const float vec[3], short adr[2])       /* clips */
789 {
790         RegionView3D *rv3d= ar->regiondata;
791         float fx, fy, vec4[4];
792         
793         adr[0]= IS_CLIPPED;
794         
795         if(rv3d->rflag & RV3D_CLIPPING) {
796                 if(ED_view3d_test_clipping(rv3d, vec, 0))
797                         return;
798         }
799         
800         copy_v3_v3(vec4, vec);
801         vec4[3]= 1.0;
802         mul_m4_v4(rv3d->persmat, vec4);
803         
804         if( vec4[3] > (float)BL_NEAR_CLIP ) {   /* 0.001 is the NEAR clipping cutoff for picking */
805                 fx= (ar->winx/2)*(1 + vec4[0]/vec4[3]);
806                 
807                 if( fx>0 && fx<ar->winx) {
808                         
809                         fy= (ar->winy/2)*(1 + vec4[1]/vec4[3]);
810                         
811                         if(fy > 0.0f && fy < (float)ar->winy) {
812                                 adr[0]= (short)floor(fx); 
813                                 adr[1]= (short)floor(fy);
814                         }
815                 }
816         }
817 }
818
819 void project_int(ARegion *ar, const float vec[3], int adr[2])
820 {
821         RegionView3D *rv3d= ar->regiondata;
822         float fx, fy, vec4[4];
823         
824         copy_v3_v3(vec4, vec);
825         vec4[3]= 1.0;
826         adr[0]= (int)2140000000.0f;
827         
828         mul_m4_v4(rv3d->persmat, vec4);
829         
830         if( vec4[3] > (float)BL_NEAR_CLIP ) {   /* 0.001 is the NEAR clipping cutoff for picking */
831                 fx= (ar->winx/2)*(1 + vec4[0]/vec4[3]);
832                 
833                 if( fx>-2140000000.0f && fx<2140000000.0f) {
834                         fy= (ar->winy/2)*(1 + vec4[1]/vec4[3]);
835                         
836                         if(fy>-2140000000.0f && fy<2140000000.0f) {
837                                 adr[0]= (int)floor(fx); 
838                                 adr[1]= (int)floor(fy);
839                         }
840                 }
841         }
842 }
843
844 void project_int_noclip(ARegion *ar, const float vec[3], int adr[2])
845 {
846         RegionView3D *rv3d= ar->regiondata;
847         float fx, fy, vec4[4];
848         
849         copy_v3_v3(vec4, vec);
850         vec4[3]= 1.0;
851         
852         mul_m4_v4(rv3d->persmat, vec4);
853         
854         if( fabs(vec4[3]) > BL_NEAR_CLIP ) {
855                 fx = (ar->winx/2)*(1 + vec4[0]/vec4[3]);
856                 fy = (ar->winy/2)*(1 + vec4[1]/vec4[3]);
857                 
858                 adr[0] = (int)floor(fx); 
859                 adr[1] = (int)floor(fy);
860         }
861         else {
862                 adr[0] = ar->winx / 2;
863                 adr[1] = ar->winy / 2;
864         }
865 }
866
867 void project_short_noclip(ARegion *ar, const float vec[3], short adr[2])
868 {
869         RegionView3D *rv3d= ar->regiondata;
870         float fx, fy, vec4[4];
871         
872         copy_v3_v3(vec4, vec);
873         vec4[3]= 1.0;
874         adr[0]= IS_CLIPPED;
875         
876         mul_m4_v4(rv3d->persmat, vec4);
877         
878         if( vec4[3] > (float)BL_NEAR_CLIP ) {   /* 0.001 is the NEAR clipping cutoff for picking */
879                 fx= (ar->winx/2)*(1 + vec4[0]/vec4[3]);
880                 
881                 if( fx>-32700 && fx<32700) {
882                         
883                         fy= (ar->winy/2)*(1 + vec4[1]/vec4[3]);
884                         
885                         if(fy > -32700.0f && fy < 32700.0f) {
886                                 adr[0]= (short)floor(fx); 
887                                 adr[1]= (short)floor(fy);
888                         }
889                 }
890         }
891 }
892
893 void project_float(ARegion *ar, const float vec[3], float adr[2])
894 {
895         RegionView3D *rv3d= ar->regiondata;
896         float vec4[4];
897         
898         copy_v3_v3(vec4, vec);
899         vec4[3]= 1.0;
900         adr[0]= IS_CLIPPED;
901         
902         mul_m4_v4(rv3d->persmat, vec4);
903         
904         if(vec4[3] > (float)BL_NEAR_CLIP) {
905                 adr[0] = (float)(ar->winx/2.0f)+(ar->winx/2.0f)*vec4[0]/vec4[3];
906                 adr[1] = (float)(ar->winy/2.0f)+(ar->winy/2.0f)*vec4[1]/vec4[3];
907         }
908 }
909
910 void project_float_noclip(ARegion *ar, const float vec[3], float adr[2])
911 {
912         RegionView3D *rv3d= ar->regiondata;
913         float vec4[4];
914         
915         copy_v3_v3(vec4, vec);
916         vec4[3]= 1.0;
917         
918         mul_m4_v4(rv3d->persmat, vec4);
919         
920         if( fabs(vec4[3]) > BL_NEAR_CLIP ) {
921                 adr[0] = (float)(ar->winx/2.0f)+(ar->winx/2.0f)*vec4[0]/vec4[3];
922                 adr[1] = (float)(ar->winy/2.0f)+(ar->winy/2.0f)*vec4[1]/vec4[3];
923         }
924         else {
925                 adr[0] = ar->winx / 2.0f;
926                 adr[1] = ar->winy / 2.0f;
927         }
928 }
929
930 /* copies logic of get_view3d_viewplane(), keep in sync */
931 int ED_view3d_clip_range_get(View3D *v3d, RegionView3D *rv3d, float *clipsta, float *clipend)
932 {
933         int orth= 0;
934
935         *clipsta= v3d->near;
936         *clipend= v3d->far;
937
938         if(rv3d->persp==RV3D_CAMOB) {
939                 if(v3d->camera) {
940                         if(v3d->camera->type==OB_LAMP ) {
941                                 Lamp *la= v3d->camera->data;
942                                 *clipsta= la->clipsta;
943                                 *clipend= la->clipend;
944                         }
945                         else if(v3d->camera->type==OB_CAMERA) {
946                                 Camera *cam= v3d->camera->data;
947                                 *clipsta= cam->clipsta;
948                                 *clipend= cam->clipend;
949
950                                 if(cam->type==CAM_ORTHO)
951                                         orth= 1;
952                         }
953                 }
954         }
955
956         if(rv3d->persp==RV3D_ORTHO) {
957                 *clipend *= 0.5f;       // otherwise too extreme low zbuffer quality
958                 *clipsta= - *clipend;
959                 orth= 1;
960         }
961
962         return orth;
963 }
964
965 /* also exposed in previewrender.c */
966 int ED_view3d_viewplane_get(View3D *v3d, RegionView3D *rv3d, int winxi, int winyi, rctf *viewplane, float *clipsta, float *clipend, float *pixsize)
967 {
968         Camera *cam=NULL;
969         float lens, sensor_x =DEFAULT_SENSOR_WIDTH, sensor_y= DEFAULT_SENSOR_HEIGHT, fac, x1, y1, x2, y2;
970         float winx= (float)winxi, winy= (float)winyi;
971         int orth= 0;
972         short fov_mode= CAMERA_FOV_AUTO;
973         
974         lens= v3d->lens;        
975         
976         *clipsta= v3d->near;
977         *clipend= v3d->far;
978         
979         if(rv3d->persp==RV3D_CAMOB) {
980                 if(v3d->camera) {
981                         if(v3d->camera->type==OB_LAMP ) {
982                                 Lamp *la;
983                                 
984                                 la= v3d->camera->data;
985                                 fac= cosf(((float)M_PI)*la->spotsize/360.0f);
986                                 
987                                 x1= saacos(fac);
988                                 lens= 16.0f*fac/sinf(x1);
989                                 
990                                 *clipsta= la->clipsta;
991                                 *clipend= la->clipend;
992                         }
993                         else if(v3d->camera->type==OB_CAMERA) {
994                                 cam= v3d->camera->data;
995                                 lens= cam->lens;
996                                 sensor_x= cam->sensor_x;
997                                 sensor_y= cam->sensor_y;
998                                 *clipsta= cam->clipsta;
999                                 *clipend= cam->clipend;
1000                                 fov_mode= cam->fov_mode;
1001                         }
1002                 }
1003         }
1004         
1005         if(rv3d->persp==RV3D_ORTHO) {
1006                 if(winx>winy) x1= -rv3d->dist;
1007                 else x1= -winx*rv3d->dist/winy;
1008                 x2= -x1;
1009                 
1010                 if(winx>winy) y1= -winy*rv3d->dist/winx;
1011                 else y1= -rv3d->dist;
1012                 y2= -y1;
1013                 
1014                 *clipend *= 0.5f;       // otherwise too extreme low zbuffer quality
1015                 *clipsta= - *clipend;
1016                 orth= 1;
1017         }
1018         else {
1019                 /* fac for zoom, also used for camdx */
1020                 if(rv3d->persp==RV3D_CAMOB) {
1021                         fac= BKE_screen_view3d_zoom_to_fac((float)rv3d->camzoom) * 4.0f;
1022                 }
1023                 else {
1024                         fac= 2.0;
1025                 }
1026                 
1027                 /* viewplane size depends... */
1028                 if(cam && cam->type==CAM_ORTHO) {
1029                         /* ortho_scale == 1 means exact 1 to 1 mapping */
1030                         float dfac= 2.0f*cam->ortho_scale/fac;
1031
1032                         if(fov_mode==CAMERA_FOV_AUTO) {
1033                                 if(winx>winy) {
1034                                         x1= -dfac;
1035                                         y1= -winy*dfac/winx;
1036                                 }
1037                                 else {
1038                                         x1= -winx*dfac/winy;
1039                                         y1= -dfac;
1040                                 }
1041                         }
1042                         else if(fov_mode==CAMERA_FOV_HOR) {
1043                                 x1= -dfac;
1044                                 y1= -winy*dfac/winx;
1045                         }
1046                         else {
1047                                 x1= -winx*dfac/winy;
1048                                 y1= -dfac;
1049                         }
1050
1051                         x2= -x1;
1052                         y2= -y1;
1053
1054                         orth= 1;
1055                 }
1056                 else {
1057                         float dfac;
1058                         
1059                         if(fov_mode==CAMERA_FOV_AUTO) {
1060                                 if(winx>winy) dfac= (sensor_x * 2.0) / (fac*winx*lens);
1061                                 else dfac= (sensor_x * 2.0) / (fac*winy*lens);
1062                         }
1063                         else if(fov_mode==CAMERA_FOV_HOR) {
1064                                 dfac= (sensor_x * 2.0) / (fac*winx*lens);
1065                         }
1066                         else {
1067                                 dfac= (sensor_y * 2.0) / (fac*winy*lens);
1068                         }
1069                         
1070                         x1= - *clipsta * winx*dfac;
1071                         x2= -x1;
1072                         y1= - *clipsta * winy*dfac;
1073                         y2= -y1;
1074                         orth= 0;
1075                 }
1076                 /* cam view offset */
1077                 if(cam) {
1078                         float dx= 0.5f*fac*rv3d->camdx*(x2-x1);
1079                         float dy= 0.5f*fac*rv3d->camdy*(y2-y1);
1080
1081                         /* shift offset */              
1082                         if(cam->type==CAM_ORTHO) {
1083                                 dx += cam->shiftx * cam->ortho_scale;
1084                                 dy += cam->shifty * cam->ortho_scale;
1085                         }
1086                         else {
1087                                 dx += cam->shiftx * (cam->clipsta / cam->lens) * sensor_x;
1088                                 dy += cam->shifty * (cam->clipsta / cam->lens) * sensor_x;
1089                         }
1090
1091                         x1+= dx;
1092                         x2+= dx;
1093                         y1+= dy;
1094                         y2+= dy;
1095                 }
1096         }
1097         
1098         if(pixsize) {
1099                 float viewfac;
1100                 
1101                 if(orth) {
1102                         viewfac= (winx >= winy)? winx: winy;
1103                         *pixsize= 1.0f/viewfac;
1104                 }
1105                 else {
1106                         viewfac= (((winx >= winy)? winx: winy)*lens)/32.0f;
1107                         *pixsize= *clipsta/viewfac;
1108                 }
1109         }
1110         
1111         viewplane->xmin= x1;
1112         viewplane->ymin= y1;
1113         viewplane->xmax= x2;
1114         viewplane->ymax= y2;
1115         
1116         return orth;
1117 }
1118
1119 void setwinmatrixview3d(ARegion *ar, View3D *v3d, rctf *rect)           /* rect: for picking */
1120 {
1121         RegionView3D *rv3d= ar->regiondata;
1122         rctf viewplane;
1123         float clipsta, clipend, x1, y1, x2, y2;
1124         int orth;
1125         
1126         orth= ED_view3d_viewplane_get(v3d, rv3d, ar->winx, ar->winy, &viewplane, &clipsta, &clipend, NULL);
1127         rv3d->is_persp= !orth;
1128
1129         //      printf("%d %d %f %f %f %f %f %f\n", winx, winy, viewplane.xmin, viewplane.ymin, viewplane.xmax, viewplane.ymax, clipsta, clipend);
1130         x1= viewplane.xmin;
1131         y1= viewplane.ymin;
1132         x2= viewplane.xmax;
1133         y2= viewplane.ymax;
1134         
1135         if(rect) {              /* picking */
1136                 rect->xmin/= (float)ar->winx;
1137                 rect->xmin= x1+rect->xmin*(x2-x1);
1138                 rect->ymin/= (float)ar->winy;
1139                 rect->ymin= y1+rect->ymin*(y2-y1);
1140                 rect->xmax/= (float)ar->winx;
1141                 rect->xmax= x1+rect->xmax*(x2-x1);
1142                 rect->ymax/= (float)ar->winy;
1143                 rect->ymax= y1+rect->ymax*(y2-y1);
1144                 
1145                 if(orth) wmOrtho(rect->xmin, rect->xmax, rect->ymin, rect->ymax, -clipend, clipend);
1146                 else wmFrustum(rect->xmin, rect->xmax, rect->ymin, rect->ymax, clipsta, clipend);
1147                 
1148         }
1149         else {
1150                 if(orth) wmOrtho(x1, x2, y1, y2, clipsta, clipend);
1151                 else wmFrustum(x1, x2, y1, y2, clipsta, clipend);
1152         }
1153
1154         /* update matrix in 3d view region */
1155         glGetFloatv(GL_PROJECTION_MATRIX, (float*)rv3d->winmat);
1156 }
1157
1158 static void obmat_to_viewmat(View3D *v3d, RegionView3D *rv3d, Object *ob, short smooth)
1159 {
1160         float bmat[4][4];
1161         float tmat[3][3];
1162         
1163         rv3d->view= RV3D_VIEW_USER; /* dont show the grid */
1164         
1165         copy_m4_m4(bmat, ob->obmat);
1166         normalize_m4(bmat);
1167         invert_m4_m4(rv3d->viewmat, bmat);
1168         
1169         /* view quat calculation, needed for add object */
1170         copy_m3_m4(tmat, rv3d->viewmat);
1171         if (smooth) {
1172                 float new_quat[4];
1173                 if (rv3d->persp==RV3D_CAMOB && v3d->camera) {
1174                         /* were from a camera view */
1175                         
1176                         float orig_ofs[3];
1177                         float orig_dist= rv3d->dist;
1178                         float orig_lens= v3d->lens;
1179                         copy_v3_v3(orig_ofs, rv3d->ofs);
1180                         
1181                         /* Switch from camera view */
1182                         mat3_to_quat( new_quat,tmat);
1183                         
1184                         rv3d->persp=RV3D_PERSP;
1185                         rv3d->dist= 0.0;
1186                         
1187                         ED_view3d_from_object(v3d->camera, rv3d->ofs, NULL, NULL, &v3d->lens);
1188                         smooth_view(NULL, NULL, NULL, NULL, NULL, orig_ofs, new_quat, &orig_dist, &orig_lens); // XXX
1189                         
1190                         rv3d->persp=RV3D_CAMOB; /* just to be polite, not needed */
1191                         
1192                 } else {
1193                         mat3_to_quat( new_quat,tmat);
1194                         smooth_view(NULL, NULL, NULL, NULL, NULL, NULL, new_quat, NULL, NULL); // XXX
1195                 }
1196         } else {
1197                 mat3_to_quat( rv3d->viewquat,tmat);
1198         }
1199 }
1200
1201 #define QUATSET(a, b, c, d, e)  a[0]=b; a[1]=c; a[2]=d; a[3]=e; 
1202
1203 int ED_view3d_lock(RegionView3D *rv3d)
1204 {
1205         switch(rv3d->view) {
1206         case RV3D_VIEW_BOTTOM :
1207                 QUATSET(rv3d->viewquat,0.0, -1.0, 0.0, 0.0);
1208                 break;
1209
1210         case RV3D_VIEW_BACK:
1211                 QUATSET(rv3d->viewquat,0.0, 0.0, (float)-cos(M_PI/4.0), (float)-cos(M_PI/4.0));
1212                 break;
1213
1214         case RV3D_VIEW_LEFT:
1215                 QUATSET(rv3d->viewquat,0.5, -0.5, 0.5, 0.5);
1216                 break;
1217
1218         case RV3D_VIEW_TOP:
1219                 QUATSET(rv3d->viewquat,1.0, 0.0, 0.0, 0.0);
1220                 break;
1221
1222         case RV3D_VIEW_FRONT:
1223                 QUATSET(rv3d->viewquat,(float)cos(M_PI/4.0), (float)-sin(M_PI/4.0), 0.0, 0.0);
1224                 break;
1225
1226         case RV3D_VIEW_RIGHT:
1227                 QUATSET(rv3d->viewquat, 0.5, -0.5, -0.5, -0.5);
1228                 break;
1229         default:
1230                 return FALSE;
1231         }
1232
1233         return TRUE;
1234 }
1235
1236 /* dont set windows active in here, is used by renderwin too */
1237 void setviewmatrixview3d(Scene *scene, View3D *v3d, RegionView3D *rv3d)
1238 {
1239         if(rv3d->persp==RV3D_CAMOB) {       /* obs/camera */
1240                 if(v3d->camera) {
1241                         where_is_object(scene, v3d->camera);    
1242                         obmat_to_viewmat(v3d, rv3d, v3d->camera, 0);
1243                 }
1244                 else {
1245                         quat_to_mat4( rv3d->viewmat,rv3d->viewquat);
1246                         rv3d->viewmat[3][2]-= rv3d->dist;
1247                 }
1248         }
1249         else {
1250                 /* should be moved to better initialize later on XXX */
1251                 if(rv3d->viewlock)
1252                         ED_view3d_lock(rv3d);
1253                 
1254                 quat_to_mat4( rv3d->viewmat,rv3d->viewquat);
1255                 if(rv3d->persp==RV3D_PERSP) rv3d->viewmat[3][2]-= rv3d->dist;
1256                 if(v3d->ob_centre) {
1257                         Object *ob= v3d->ob_centre;
1258                         float vec[3];
1259                         
1260                         copy_v3_v3(vec, ob->obmat[3]);
1261                         if(ob->type==OB_ARMATURE && v3d->ob_centre_bone[0]) {
1262                                 bPoseChannel *pchan= get_pose_channel(ob->pose, v3d->ob_centre_bone);
1263                                 if(pchan) {
1264                                         copy_v3_v3(vec, pchan->pose_mat[3]);
1265                                         mul_m4_v3(ob->obmat, vec);
1266                                 }
1267                         }
1268                         translate_m4( rv3d->viewmat,-vec[0], -vec[1], -vec[2]);
1269                 }
1270                 else if (v3d->ob_centre_cursor) {
1271                         float vec[3];
1272                         copy_v3_v3(vec, give_cursor(scene, v3d));
1273                         translate_m4(rv3d->viewmat, -vec[0], -vec[1], -vec[2]);
1274                 }
1275                 else translate_m4( rv3d->viewmat,rv3d->ofs[0], rv3d->ofs[1], rv3d->ofs[2]);
1276         }
1277 }
1278
1279 /* IGLuint-> GLuint*/
1280 /* Warning: be sure to account for a negative return value
1281 *   This is an error, "Too many objects in select buffer"
1282 *   and no action should be taken (can crash blender) if this happens
1283 */
1284 short view3d_opengl_select(ViewContext *vc, unsigned int *buffer, unsigned int bufsize, rcti *input)
1285 {
1286         Scene *scene= vc->scene;
1287         View3D *v3d= vc->v3d;
1288         ARegion *ar= vc->ar;
1289         rctf rect;
1290         short code, hits;
1291         char dt, dtx;
1292         
1293         G.f |= G_PICKSEL;
1294         
1295         /* case not a border select */
1296         if(input->xmin==input->xmax) {
1297                 rect.xmin= input->xmin-12;      // seems to be default value for bones only now
1298                 rect.xmax= input->xmin+12;
1299                 rect.ymin= input->ymin-12;
1300                 rect.ymax= input->ymin+12;
1301         }
1302         else {
1303                 rect.xmin= input->xmin;
1304                 rect.xmax= input->xmax;
1305                 rect.ymin= input->ymin;
1306                 rect.ymax= input->ymax;
1307         }
1308         
1309         setwinmatrixview3d(ar, v3d, &rect);
1310         mul_m4_m4m4(vc->rv3d->persmat, vc->rv3d->viewmat, vc->rv3d->winmat);
1311         
1312         if(v3d->drawtype > OB_WIRE) {
1313                 v3d->zbuf= TRUE;
1314                 glEnable(GL_DEPTH_TEST);
1315         }
1316         
1317         if(vc->rv3d->rflag & RV3D_CLIPPING)
1318                 view3d_set_clipping(vc->rv3d);
1319         
1320         glSelectBuffer( bufsize, (GLuint *)buffer);
1321         glRenderMode(GL_SELECT);
1322         glInitNames();  /* these two calls whatfor? It doesnt work otherwise */
1323         glPushName(-1);
1324         code= 1;
1325         
1326         if(vc->obedit && vc->obedit->type==OB_MBALL) {
1327                 draw_object(scene, ar, v3d, BASACT, DRAW_PICKING|DRAW_CONSTCOLOR);
1328         }
1329         else if((vc->obedit && vc->obedit->type==OB_ARMATURE)) {
1330                 /* if not drawing sketch, draw bones */
1331                 if(!BDR_drawSketchNames(vc)) {
1332                         draw_object(scene, ar, v3d, BASACT, DRAW_PICKING|DRAW_CONSTCOLOR);
1333                 }
1334         }
1335         else {
1336                 Base *base;
1337                 
1338                 v3d->xray= TRUE;        // otherwise it postpones drawing
1339                 for(base= scene->base.first; base; base= base->next) {
1340                         if(base->lay & v3d->lay) {
1341                                 
1342                                 if (base->object->restrictflag & OB_RESTRICT_SELECT)
1343                                         base->selcol= 0;
1344                                 else {
1345                                         base->selcol= code;
1346                                         glLoadName(code);
1347                                         draw_object(scene, ar, v3d, base, DRAW_PICKING|DRAW_CONSTCOLOR);
1348                                         
1349                                         /* we draw group-duplicators for selection too */
1350                                         if((base->object->transflag & OB_DUPLI) && base->object->dup_group) {
1351                                                 ListBase *lb;
1352                                                 DupliObject *dob;
1353                                                 Base tbase;
1354                                                 
1355                                                 tbase.flag= OB_FROMDUPLI;
1356                                                 lb= object_duplilist(scene, base->object);
1357                                                 
1358                                                 for(dob= lb->first; dob; dob= dob->next) {
1359                                                         tbase.object= dob->ob;
1360                                                         copy_m4_m4(dob->ob->obmat, dob->mat);
1361                                                         
1362                                                         /* extra service: draw the duplicator in drawtype of parent */
1363                                                         /* MIN2 for the drawtype to allow bounding box objects in groups for lods */
1364                                                         dt= tbase.object->dt;   tbase.object->dt= MIN2(tbase.object->dt, base->object->dt);
1365                                                         dtx= tbase.object->dtx; tbase.object->dtx= base->object->dtx;
1366
1367                                                         draw_object(scene, ar, v3d, &tbase, DRAW_PICKING|DRAW_CONSTCOLOR);
1368                                                         
1369                                                         tbase.object->dt= dt;
1370                                                         tbase.object->dtx= dtx;
1371
1372                                                         copy_m4_m4(dob->ob->obmat, dob->omat);
1373                                                 }
1374                                                 free_object_duplilist(lb);
1375                                         }
1376                                         code++;
1377                                 }                               
1378                         }
1379                 }
1380                 v3d->xray= FALSE;       // restore
1381         }
1382         
1383         glPopName();    /* see above (pushname) */
1384         hits= glRenderMode(GL_RENDER);
1385         
1386         G.f &= ~G_PICKSEL;
1387         setwinmatrixview3d(ar, v3d, NULL);
1388         mul_m4_m4m4(vc->rv3d->persmat, vc->rv3d->viewmat, vc->rv3d->winmat);
1389         
1390         if(v3d->drawtype > OB_WIRE) {
1391                 v3d->zbuf= 0;
1392                 glDisable(GL_DEPTH_TEST);
1393         }
1394 // XXX  persp(PERSP_WIN);
1395         
1396         if(vc->rv3d->rflag & RV3D_CLIPPING)
1397                 view3d_clr_clipping();
1398         
1399         if(hits<0) printf("Too many objects in select buffer\n");       // XXX make error message
1400         
1401         return hits;
1402 }
1403
1404 /* ********************** local view operator ******************** */
1405
1406 static unsigned int free_localbit(Main *bmain)
1407 {
1408         unsigned int lay;
1409         ScrArea *sa;
1410         bScreen *sc;
1411         
1412         lay= 0;
1413         
1414         /* sometimes we loose a localview: when an area is closed */
1415         /* check all areas: which localviews are in use? */
1416         for(sc= bmain->screen.first; sc; sc= sc->id.next) {
1417                 for(sa= sc->areabase.first; sa; sa= sa->next) {
1418                         SpaceLink *sl= sa->spacedata.first;
1419                         for(; sl; sl= sl->next) {
1420                                 if(sl->spacetype==SPACE_VIEW3D) {
1421                                         View3D *v3d= (View3D*) sl;
1422                                         lay |= v3d->lay;
1423                                 }
1424                         }
1425                 }
1426         }
1427         
1428         if( (lay & 0x01000000)==0) return 0x01000000;
1429         if( (lay & 0x02000000)==0) return 0x02000000;
1430         if( (lay & 0x04000000)==0) return 0x04000000;
1431         if( (lay & 0x08000000)==0) return 0x08000000;
1432         if( (lay & 0x10000000)==0) return 0x10000000;
1433         if( (lay & 0x20000000)==0) return 0x20000000;
1434         if( (lay & 0x40000000)==0) return 0x40000000;
1435         if( (lay & 0x80000000)==0) return 0x80000000;
1436         
1437         return 0;
1438 }
1439
1440 int ED_view3d_scene_layer_set(int lay, const int *values, int *active)
1441 {
1442         int i, tot= 0;
1443         
1444         /* ensure we always have some layer selected */
1445         for(i=0; i<20; i++)
1446                 if(values[i])
1447                         tot++;
1448         
1449         if(tot==0)
1450                 return lay;
1451         
1452         for(i=0; i<20; i++) {
1453                 
1454                 if (active) {
1455                         /* if this value has just been switched on, make that layer active */
1456                         if (values[i] && (lay & (1<<i))==0) {
1457                                 *active = (1<<i);
1458                         }
1459                 }
1460                         
1461                 if (values[i]) lay |= (1<<i);
1462                 else lay &= ~(1<<i);
1463         }
1464         
1465         /* ensure always an active layer */
1466         if (active && (lay & *active)==0) {
1467                 for(i=0; i<20; i++) {
1468                         if(lay & (1<<i)) {
1469                                 *active= 1<<i;
1470                                 break;
1471                         }
1472                 }
1473         }
1474         
1475         return lay;
1476 }
1477
1478 static void initlocalview(Main *bmain, Scene *scene, ScrArea *sa)
1479 {
1480         View3D *v3d= sa->spacedata.first;
1481         Base *base;
1482         float size = 0.0, min[3], max[3], box[3];
1483         unsigned int locallay;
1484         int ok=0;
1485
1486         if(v3d->localvd) return;
1487
1488         INIT_MINMAX(min, max);
1489
1490         locallay= free_localbit(bmain);
1491
1492         if(locallay==0) {
1493                 printf("Sorry, no more than 8 localviews\n");   // XXX error 
1494                 ok= 0;
1495         }
1496         else {
1497                 if(scene->obedit) {
1498                         minmax_object(scene->obedit, min, max);
1499                         
1500                         ok= 1;
1501                 
1502                         BASACT->lay |= locallay;
1503                         scene->obedit->lay= BASACT->lay;
1504                 }
1505                 else {
1506                         for(base= FIRSTBASE; base; base= base->next) {
1507                                 if(TESTBASE(v3d, base))  {
1508                                         minmax_object(base->object, min, max);
1509                                         base->lay |= locallay;
1510                                         base->object->lay= base->lay;
1511                                         ok= 1;
1512                                 }
1513                         }
1514                 }
1515                 
1516                 box[0]= (max[0]-min[0]);
1517                 box[1]= (max[1]-min[1]);
1518                 box[2]= (max[2]-min[2]);
1519                 size= MAX3(box[0], box[1], box[2]);
1520                 if(size <= 0.01f) size= 0.01f;
1521         }
1522         
1523         if(ok) {
1524                 ARegion *ar;
1525                 
1526                 v3d->localvd= MEM_mallocN(sizeof(View3D), "localview");
1527                 
1528                 memcpy(v3d->localvd, v3d, sizeof(View3D));
1529
1530                 for(ar= sa->regionbase.first; ar; ar= ar->next) {
1531                         if(ar->regiontype == RGN_TYPE_WINDOW) {
1532                                 RegionView3D *rv3d= ar->regiondata;
1533
1534                                 rv3d->localvd= MEM_mallocN(sizeof(RegionView3D), "localview region");
1535                                 memcpy(rv3d->localvd, rv3d, sizeof(RegionView3D));
1536                                 
1537                                 rv3d->ofs[0]= -(min[0]+max[0])/2.0f;
1538                                 rv3d->ofs[1]= -(min[1]+max[1])/2.0f;
1539                                 rv3d->ofs[2]= -(min[2]+max[2])/2.0f;
1540
1541                                 rv3d->dist= size;
1542                                 /* perspective should be a bit farther away to look nice */
1543                                 if(rv3d->persp==RV3D_ORTHO)
1544                                         rv3d->dist*= 0.7f;
1545
1546                                 // correction for window aspect ratio
1547                                 if(ar->winy>2 && ar->winx>2) {
1548                                         float asp= (float)ar->winx/(float)ar->winy;
1549                                         if(asp < 1.0f) asp= 1.0f/asp;
1550                                         rv3d->dist*= asp;
1551                                 }
1552                                 
1553                                 if (rv3d->persp==RV3D_CAMOB) rv3d->persp= RV3D_PERSP;
1554                                 
1555                                 v3d->cursor[0]= -rv3d->ofs[0];
1556                                 v3d->cursor[1]= -rv3d->ofs[1];
1557                                 v3d->cursor[2]= -rv3d->ofs[2];
1558                         }
1559                 }
1560                 
1561                 v3d->lay= locallay;
1562         }
1563         else {
1564                 /* clear flags */ 
1565                 for(base= FIRSTBASE; base; base= base->next) {
1566                         if( base->lay & locallay ) {
1567                                 base->lay-= locallay;
1568                                 if(base->lay==0) base->lay= v3d->layact;
1569                                 if(base->object != scene->obedit) base->flag |= SELECT;
1570                                 base->object->lay= base->lay;
1571                         }
1572                 }               
1573         }
1574
1575 }
1576
1577 static void restore_localviewdata(ScrArea *sa, int free)
1578 {
1579         ARegion *ar;
1580         View3D *v3d= sa->spacedata.first;
1581         
1582         if(v3d->localvd==NULL) return;
1583         
1584         v3d->near= v3d->localvd->near;
1585         v3d->far= v3d->localvd->far;
1586         v3d->lay= v3d->localvd->lay;
1587         v3d->layact= v3d->localvd->layact;
1588         v3d->drawtype= v3d->localvd->drawtype;
1589         v3d->camera= v3d->localvd->camera;
1590         
1591         if(free) {
1592                 MEM_freeN(v3d->localvd);
1593                 v3d->localvd= NULL;
1594         }
1595         
1596         for(ar= sa->regionbase.first; ar; ar= ar->next) {
1597                 if(ar->regiontype == RGN_TYPE_WINDOW) {
1598                         RegionView3D *rv3d= ar->regiondata;
1599                         
1600                         if(rv3d->localvd) {
1601                                 rv3d->dist= rv3d->localvd->dist;
1602                                 copy_v3_v3(rv3d->ofs, rv3d->localvd->ofs);
1603                                 copy_qt_qt(rv3d->viewquat, rv3d->localvd->viewquat);
1604                                 rv3d->view= rv3d->localvd->view;
1605                                 rv3d->persp= rv3d->localvd->persp;
1606                                 rv3d->camzoom= rv3d->localvd->camzoom;
1607
1608                                 if(free) {
1609                                         MEM_freeN(rv3d->localvd);
1610                                         rv3d->localvd= NULL;
1611                                 }
1612                         }
1613                 }
1614         }
1615 }
1616
1617 static void endlocalview(Main *bmain, Scene *scene, ScrArea *sa)
1618 {
1619         View3D *v3d= sa->spacedata.first;
1620         struct Base *base;
1621         unsigned int locallay;
1622         
1623         if(v3d->localvd) {
1624                 
1625                 locallay= v3d->lay & 0xFF000000;
1626                 
1627                 restore_localviewdata(sa, 1); // 1 = free
1628
1629                 /* for when in other window the layers have changed */
1630                 if(v3d->scenelock) v3d->lay= scene->lay;
1631                 
1632                 for(base= FIRSTBASE; base; base= base->next) {
1633                         if( base->lay & locallay ) {
1634                                 base->lay-= locallay;
1635                                 if(base->lay==0) base->lay= v3d->layact;
1636                                 if(base->object != scene->obedit) {
1637                                         base->flag |= SELECT;
1638                                         base->object->flag |= SELECT;
1639                                 }
1640                                 base->object->lay= base->lay;
1641                         }
1642                 }
1643                 
1644                 DAG_on_visible_update(bmain, FALSE);
1645         } 
1646 }
1647
1648 static int localview_exec(bContext *C, wmOperator *UNUSED(unused))
1649 {
1650         View3D *v3d= CTX_wm_view3d(C);
1651         
1652         if(v3d->localvd)
1653                 endlocalview(CTX_data_main(C), CTX_data_scene(C), CTX_wm_area(C));
1654         else
1655                 initlocalview(CTX_data_main(C), CTX_data_scene(C), CTX_wm_area(C));
1656         
1657         ED_area_tag_redraw(CTX_wm_area(C));
1658         
1659         return OPERATOR_FINISHED;
1660 }
1661
1662 void VIEW3D_OT_localview(wmOperatorType *ot)
1663 {
1664         
1665         /* identifiers */
1666         ot->name= "Local View";
1667         ot->description= "Toggle display of selected object(s) separately and centered in view";
1668         ot->idname= "VIEW3D_OT_localview";
1669         
1670         /* api callbacks */
1671         ot->exec= localview_exec;
1672         ot->flag= OPTYPE_UNDO; /* localview changes object layer bitflags */
1673         
1674         ot->poll= ED_operator_view3d_active;
1675 }
1676
1677 #ifdef WITH_GAMEENGINE
1678
1679 static ListBase queue_back;
1680 static void SaveState(bContext *C, wmWindow *win)
1681 {
1682         Object *obact = CTX_data_active_object(C);
1683         
1684         glPushAttrib(GL_ALL_ATTRIB_BITS);
1685
1686         if(obact && obact->mode & OB_MODE_TEXTURE_PAINT)
1687                 GPU_paint_set_mipmap(1);
1688         
1689         queue_back= win->queue;
1690         
1691         win->queue.first= win->queue.last= NULL;
1692         
1693         //XXX waitcursor(1);
1694 }
1695
1696 static void RestoreState(bContext *C, wmWindow *win)
1697 {
1698         Object *obact = CTX_data_active_object(C);
1699         
1700         if(obact && obact->mode & OB_MODE_TEXTURE_PAINT)
1701                 GPU_paint_set_mipmap(0);
1702
1703         //XXX curarea->win_swap = 0;
1704         //XXX curarea->head_swap=0;
1705         //XXX allqueue(REDRAWVIEW3D, 1);
1706         //XXX allqueue(REDRAWBUTSALL, 0);
1707         //XXX reset_slowparents();
1708         //XXX waitcursor(0);
1709         //XXX G.qual= 0;
1710         
1711         if(win) /* check because closing win can set to NULL */
1712                 win->queue= queue_back;
1713         
1714         GPU_state_init();
1715         GPU_set_tpage(NULL, 0, 0);
1716
1717         glPopAttrib();
1718 }
1719
1720 /* was space_set_commmandline_options in 2.4x */
1721 static void game_set_commmandline_options(GameData *gm)
1722 {
1723         SYS_SystemHandle syshandle;
1724         int test;
1725
1726         if ( (syshandle = SYS_GetSystem()) ) {
1727                 /* User defined settings */
1728                 test= (U.gameflags & USER_DISABLE_MIPMAP);
1729                 GPU_set_mipmap(!test);
1730                 SYS_WriteCommandLineInt(syshandle, "nomipmap", test);
1731
1732                 /* File specific settings: */
1733                 /* Only test the first one. These two are switched
1734                  * simultaneously. */
1735                 test= (gm->flag & GAME_SHOW_FRAMERATE);
1736                 SYS_WriteCommandLineInt(syshandle, "show_framerate", test);
1737                 SYS_WriteCommandLineInt(syshandle, "show_profile", test);
1738
1739                 test = (gm->flag & GAME_SHOW_DEBUG_PROPS);
1740                 SYS_WriteCommandLineInt(syshandle, "show_properties", test);
1741
1742                 test= (gm->flag & GAME_SHOW_PHYSICS);
1743                 SYS_WriteCommandLineInt(syshandle, "show_physics", test);
1744
1745                 test= (gm->flag & GAME_ENABLE_ALL_FRAMES);
1746                 SYS_WriteCommandLineInt(syshandle, "fixedtime", test);
1747
1748                 test= (gm->flag & GAME_ENABLE_ANIMATION_RECORD);
1749                 SYS_WriteCommandLineInt(syshandle, "animation_record", test);
1750
1751                 test= (gm->flag & GAME_IGNORE_DEPRECATION_WARNINGS);
1752                 SYS_WriteCommandLineInt(syshandle, "ignore_deprecation_warnings", test);
1753
1754                 test= (gm->matmode == GAME_MAT_MULTITEX);
1755                 SYS_WriteCommandLineInt(syshandle, "blender_material", test);
1756                 test= (gm->matmode == GAME_MAT_GLSL);
1757                 SYS_WriteCommandLineInt(syshandle, "blender_glsl_material", test);
1758                 test= (gm->flag & GAME_DISPLAY_LISTS);
1759                 SYS_WriteCommandLineInt(syshandle, "displaylists", test);
1760
1761
1762         }
1763 }
1764
1765 #endif // WITH_GAMEENGINE
1766
1767 static int game_engine_poll(bContext *C)
1768 {
1769         /* we need a context and area to launch BGE
1770         it's a temporary solution to avoid crash at load time
1771         if we try to auto run the BGE. Ideally we want the
1772         context to be set as soon as we load the file. */
1773
1774         if(CTX_wm_window(C)==NULL) return 0;
1775         if(CTX_wm_screen(C)==NULL) return 0;
1776         if(CTX_wm_area(C)==NULL) return 0;
1777
1778         if(CTX_data_mode_enum(C)!=CTX_MODE_OBJECT)
1779                 return 0;
1780
1781         return 1;
1782 }
1783
1784 int ED_view3d_context_activate(bContext *C)
1785 {
1786         bScreen *sc= CTX_wm_screen(C);
1787         ScrArea *sa= CTX_wm_area(C);
1788         ARegion *ar;
1789
1790         /* sa can be NULL when called from python */
1791         if(sa==NULL || sa->spacetype != SPACE_VIEW3D)
1792                 for(sa=sc->areabase.first; sa; sa= sa->next)
1793                         if(sa->spacetype==SPACE_VIEW3D)
1794                                 break;
1795
1796         if(!sa)
1797                 return 0;
1798         
1799         for(ar=sa->regionbase.first; ar; ar=ar->next)
1800                 if(ar->regiontype == RGN_TYPE_WINDOW)
1801                         break;
1802         
1803         if(!ar)
1804                 return 0;
1805         
1806         // bad context switch ..
1807         CTX_wm_area_set(C, sa);
1808         CTX_wm_region_set(C, ar);
1809
1810         return 1;
1811 }
1812
1813 static int game_engine_exec(bContext *C, wmOperator *op)
1814 {
1815 #ifdef WITH_GAMEENGINE
1816         Scene *startscene = CTX_data_scene(C);
1817         ScrArea /* *sa, */ /* UNUSED */ *prevsa= CTX_wm_area(C);
1818         ARegion *ar, *prevar= CTX_wm_region(C);
1819         wmWindow *prevwin= CTX_wm_window(C);
1820         RegionView3D *rv3d;
1821         rcti cam_frame;
1822
1823         (void)op; /* unused */
1824         
1825         // bad context switch ..
1826         if(!ED_view3d_context_activate(C))
1827                 return OPERATOR_CANCELLED;
1828         
1829         rv3d= CTX_wm_region_view3d(C);
1830         /* sa= CTX_wm_area(C); */ /* UNUSED */
1831         ar= CTX_wm_region(C);
1832
1833         view3d_operator_needs_opengl(C);
1834         
1835         game_set_commmandline_options(&startscene->gm);
1836
1837         if(rv3d->persp==RV3D_CAMOB && startscene->gm.framing.type == SCE_GAMEFRAMING_BARS && startscene->gm.stereoflag != STEREO_DOME) { /* Letterbox */
1838                 rctf cam_framef;
1839                 ED_view3d_calc_camera_border(startscene, ar, CTX_wm_view3d(C), rv3d, &cam_framef, FALSE);
1840                 cam_frame.xmin = cam_framef.xmin + ar->winrct.xmin;
1841                 cam_frame.xmax = cam_framef.xmax + ar->winrct.xmin;
1842                 cam_frame.ymin = cam_framef.ymin + ar->winrct.ymin;
1843                 cam_frame.ymax = cam_framef.ymax + ar->winrct.ymin;
1844                 BLI_isect_rcti(&ar->winrct, &cam_frame, &cam_frame);
1845         }
1846         else {
1847                 cam_frame.xmin = ar->winrct.xmin;
1848                 cam_frame.xmax = ar->winrct.xmax;
1849                 cam_frame.ymin = ar->winrct.ymin;
1850                 cam_frame.ymax = ar->winrct.ymax;
1851         }
1852
1853
1854         SaveState(C, prevwin);
1855
1856         StartKetsjiShell(C, ar, &cam_frame, 1);
1857
1858         /* window wasnt closed while the BGE was running */
1859         if(BLI_findindex(&CTX_wm_manager(C)->windows, prevwin) == -1) {
1860                 prevwin= NULL;
1861                 CTX_wm_window_set(C, NULL);
1862         }
1863         
1864         if(prevwin) {
1865                 /* restore context, in case it changed in the meantime, for
1866                    example by working in another window or closing it */
1867                 CTX_wm_region_set(C, prevar);
1868                 CTX_wm_window_set(C, prevwin);
1869                 CTX_wm_area_set(C, prevsa);
1870         }
1871
1872         RestoreState(C, prevwin);
1873
1874         //XXX restore_all_scene_cfra(scene_cfra_store);
1875         set_scene_bg(CTX_data_main(C), startscene);
1876         //XXX scene_update_for_newframe(bmain, scene, scene->lay);
1877         
1878         ED_area_tag_redraw(CTX_wm_area(C));
1879
1880         return OPERATOR_FINISHED;
1881 #else
1882         (void)C; /* unused */
1883         BKE_report(op->reports, RPT_ERROR, "Game engine is disabled in this build");
1884         return OPERATOR_CANCELLED;
1885 #endif
1886 }
1887
1888 void VIEW3D_OT_game_start(wmOperatorType *ot)
1889 {
1890         
1891         /* identifiers */
1892         ot->name= "Start Game Engine";
1893         ot->description= "Start game engine";
1894         ot->idname= "VIEW3D_OT_game_start";
1895         
1896         /* api callbacks */
1897         ot->exec= game_engine_exec;
1898         
1899         ot->poll= game_engine_poll;
1900 }
1901
1902 /* ************************************** */
1903
1904 void view3d_align_axis_to_vector(View3D *v3d, RegionView3D *rv3d, int axisidx, float vec[3])
1905 {
1906         float alignaxis[3] = {0.0, 0.0, 0.0};
1907         float norm[3], axis[3], angle, new_quat[4];
1908         
1909         if(axisidx > 0) alignaxis[axisidx-1]= 1.0;
1910         else alignaxis[-axisidx-1]= -1.0;
1911
1912         normalize_v3_v3(norm, vec);
1913
1914         angle= (float)acos(dot_v3v3(alignaxis, norm));
1915         cross_v3_v3v3(axis, alignaxis, norm);
1916         axis_angle_to_quat( new_quat,axis, -angle);
1917         
1918         rv3d->view= RV3D_VIEW_USER;
1919         
1920         if (rv3d->persp==RV3D_CAMOB && v3d->camera) {
1921                 /* switch out of camera view */
1922                 float orig_ofs[3];
1923                 float orig_dist= rv3d->dist;
1924                 float orig_lens= v3d->lens;
1925                 
1926                 copy_v3_v3(orig_ofs, rv3d->ofs);
1927                 rv3d->persp= RV3D_PERSP;
1928                 rv3d->dist= 0.0;
1929                 ED_view3d_from_object(v3d->camera, rv3d->ofs, NULL, NULL, &v3d->lens);
1930                 smooth_view(NULL, NULL, NULL, NULL, NULL, orig_ofs, new_quat, &orig_dist, &orig_lens); // XXX
1931         } else {
1932                 if (rv3d->persp==RV3D_CAMOB) rv3d->persp= RV3D_PERSP; /* switch out of camera mode */
1933                 smooth_view(NULL, NULL, NULL, NULL, NULL, NULL, new_quat, NULL, NULL); // XXX
1934         }
1935 }
1936
1937 float ED_view3d_pixel_size(struct RegionView3D *rv3d, const float co[3])
1938 {
1939         return  (rv3d->persmat[3][3] + (
1940                                 rv3d->persmat[0][3]*co[0] +
1941                                 rv3d->persmat[1][3]*co[1] +
1942                                 rv3d->persmat[2][3]*co[2])
1943                         ) * rv3d->pixsize;
1944 }