8e0905d42d3c07446b97d4b60703e9c740109aef
[blender-staging.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=32.f, fac, x1, y1, x2, y2;
970         float winx= (float)winxi, winy= (float)winyi;
971         int orth= 0;
972         
973         lens= v3d->lens;        
974         
975         *clipsta= v3d->near;
976         *clipend= v3d->far;
977         
978         if(rv3d->persp==RV3D_CAMOB) {
979                 if(v3d->camera) {
980                         if(v3d->camera->type==OB_LAMP ) {
981                                 Lamp *la;
982                                 
983                                 la= v3d->camera->data;
984                                 fac= cosf(((float)M_PI)*la->spotsize/360.0f);
985                                 
986                                 x1= saacos(fac);
987                                 lens= 16.0f*fac/sinf(x1);
988                                 
989                                 *clipsta= la->clipsta;
990                                 *clipend= la->clipend;
991                         }
992                         else if(v3d->camera->type==OB_CAMERA) {
993                                 cam= v3d->camera->data;
994                                 lens= cam->lens;
995                                 sensor= cam->sensor_x;
996                                 *clipsta= cam->clipsta;
997                                 *clipend= cam->clipend;
998                         }
999                 }
1000         }
1001         
1002         if(rv3d->persp==RV3D_ORTHO) {
1003                 if(winx>winy) x1= -rv3d->dist;
1004                 else x1= -winx*rv3d->dist/winy;
1005                 x2= -x1;
1006                 
1007                 if(winx>winy) y1= -winy*rv3d->dist/winx;
1008                 else y1= -rv3d->dist;
1009                 y2= -y1;
1010                 
1011                 *clipend *= 0.5f;       // otherwise too extreme low zbuffer quality
1012                 *clipsta= - *clipend;
1013                 orth= 1;
1014         }
1015         else {
1016                 /* fac for zoom, also used for camdx */
1017                 if(rv3d->persp==RV3D_CAMOB) {
1018                         fac= BKE_screen_view3d_zoom_to_fac((float)rv3d->camzoom) * 4.0f;
1019                 }
1020                 else {
1021                         fac= 2.0;
1022                 }
1023                 
1024                 /* viewplane size depends... */
1025                 if(cam && cam->type==CAM_ORTHO) {
1026                         /* ortho_scale == 1 means exact 1 to 1 mapping */
1027                         float dfac= 2.0f*cam->ortho_scale/fac;
1028                         
1029                         if(winx>winy) x1= -dfac;
1030                         else x1= -winx*dfac/winy;
1031                         x2= -x1;
1032                         
1033                         if(winx>winy) y1= -winy*dfac/winx;
1034                         else y1= -dfac;
1035                         y2= -y1;
1036                         orth= 1;
1037                 }
1038                 else {
1039                         float dfac;
1040                         
1041                         if(winx>winy) dfac= (sensor * 2.0) / (fac*winx*lens);
1042                         else dfac= (sensor * 2.0) / (fac*winy*lens);
1043                         
1044                         x1= - *clipsta * winx*dfac;
1045                         x2= -x1;
1046                         y1= - *clipsta * winy*dfac;
1047                         y2= -y1;
1048                         orth= 0;
1049                 }
1050                 /* cam view offset */
1051                 if(cam) {
1052                         float dx= 0.5f*fac*rv3d->camdx*(x2-x1);
1053                         float dy= 0.5f*fac*rv3d->camdy*(y2-y1);
1054
1055                         /* shift offset */              
1056                         if(cam->type==CAM_ORTHO) {
1057                                 dx += cam->shiftx * cam->ortho_scale;
1058                                 dy += cam->shifty * cam->ortho_scale;
1059                         }
1060                         else {
1061                                 dx += cam->shiftx * (cam->clipsta / cam->lens) * sensor;
1062                                 dy += cam->shifty * (cam->clipsta / cam->lens) * sensor;
1063                         }
1064
1065                         x1+= dx;
1066                         x2+= dx;
1067                         y1+= dy;
1068                         y2+= dy;
1069                 }
1070         }
1071         
1072         if(pixsize) {
1073                 float viewfac;
1074                 
1075                 if(orth) {
1076                         viewfac= (winx >= winy)? winx: winy;
1077                         *pixsize= 1.0f/viewfac;
1078                 }
1079                 else {
1080                         viewfac= (((winx >= winy)? winx: winy)*lens)/32.0f;
1081                         *pixsize= *clipsta/viewfac;
1082                 }
1083         }
1084         
1085         viewplane->xmin= x1;
1086         viewplane->ymin= y1;
1087         viewplane->xmax= x2;
1088         viewplane->ymax= y2;
1089         
1090         return orth;
1091 }
1092
1093 void setwinmatrixview3d(ARegion *ar, View3D *v3d, rctf *rect)           /* rect: for picking */
1094 {
1095         RegionView3D *rv3d= ar->regiondata;
1096         rctf viewplane;
1097         float clipsta, clipend, x1, y1, x2, y2;
1098         int orth;
1099         
1100         orth= ED_view3d_viewplane_get(v3d, rv3d, ar->winx, ar->winy, &viewplane, &clipsta, &clipend, NULL);
1101         rv3d->is_persp= !orth;
1102
1103         //      printf("%d %d %f %f %f %f %f %f\n", winx, winy, viewplane.xmin, viewplane.ymin, viewplane.xmax, viewplane.ymax, clipsta, clipend);
1104         x1= viewplane.xmin;
1105         y1= viewplane.ymin;
1106         x2= viewplane.xmax;
1107         y2= viewplane.ymax;
1108         
1109         if(rect) {              /* picking */
1110                 rect->xmin/= (float)ar->winx;
1111                 rect->xmin= x1+rect->xmin*(x2-x1);
1112                 rect->ymin/= (float)ar->winy;
1113                 rect->ymin= y1+rect->ymin*(y2-y1);
1114                 rect->xmax/= (float)ar->winx;
1115                 rect->xmax= x1+rect->xmax*(x2-x1);
1116                 rect->ymax/= (float)ar->winy;
1117                 rect->ymax= y1+rect->ymax*(y2-y1);
1118                 
1119                 if(orth) wmOrtho(rect->xmin, rect->xmax, rect->ymin, rect->ymax, -clipend, clipend);
1120                 else wmFrustum(rect->xmin, rect->xmax, rect->ymin, rect->ymax, clipsta, clipend);
1121                 
1122         }
1123         else {
1124                 if(orth) wmOrtho(x1, x2, y1, y2, clipsta, clipend);
1125                 else wmFrustum(x1, x2, y1, y2, clipsta, clipend);
1126         }
1127
1128         /* update matrix in 3d view region */
1129         glGetFloatv(GL_PROJECTION_MATRIX, (float*)rv3d->winmat);
1130 }
1131
1132 static void obmat_to_viewmat(View3D *v3d, RegionView3D *rv3d, Object *ob, short smooth)
1133 {
1134         float bmat[4][4];
1135         float tmat[3][3];
1136         
1137         rv3d->view= RV3D_VIEW_USER; /* dont show the grid */
1138         
1139         copy_m4_m4(bmat, ob->obmat);
1140         normalize_m4(bmat);
1141         invert_m4_m4(rv3d->viewmat, bmat);
1142         
1143         /* view quat calculation, needed for add object */
1144         copy_m3_m4(tmat, rv3d->viewmat);
1145         if (smooth) {
1146                 float new_quat[4];
1147                 if (rv3d->persp==RV3D_CAMOB && v3d->camera) {
1148                         /* were from a camera view */
1149                         
1150                         float orig_ofs[3];
1151                         float orig_dist= rv3d->dist;
1152                         float orig_lens= v3d->lens;
1153                         copy_v3_v3(orig_ofs, rv3d->ofs);
1154                         
1155                         /* Switch from camera view */
1156                         mat3_to_quat( new_quat,tmat);
1157                         
1158                         rv3d->persp=RV3D_PERSP;
1159                         rv3d->dist= 0.0;
1160                         
1161                         ED_view3d_from_object(v3d->camera, rv3d->ofs, NULL, NULL, &v3d->lens);
1162                         smooth_view(NULL, NULL, NULL, NULL, NULL, orig_ofs, new_quat, &orig_dist, &orig_lens); // XXX
1163                         
1164                         rv3d->persp=RV3D_CAMOB; /* just to be polite, not needed */
1165                         
1166                 } else {
1167                         mat3_to_quat( new_quat,tmat);
1168                         smooth_view(NULL, NULL, NULL, NULL, NULL, NULL, new_quat, NULL, NULL); // XXX
1169                 }
1170         } else {
1171                 mat3_to_quat( rv3d->viewquat,tmat);
1172         }
1173 }
1174
1175 #define QUATSET(a, b, c, d, e)  a[0]=b; a[1]=c; a[2]=d; a[3]=e; 
1176
1177 int ED_view3d_lock(RegionView3D *rv3d)
1178 {
1179         switch(rv3d->view) {
1180         case RV3D_VIEW_BOTTOM :
1181                 QUATSET(rv3d->viewquat,0.0, -1.0, 0.0, 0.0);
1182                 break;
1183
1184         case RV3D_VIEW_BACK:
1185                 QUATSET(rv3d->viewquat,0.0, 0.0, (float)-cos(M_PI/4.0), (float)-cos(M_PI/4.0));
1186                 break;
1187
1188         case RV3D_VIEW_LEFT:
1189                 QUATSET(rv3d->viewquat,0.5, -0.5, 0.5, 0.5);
1190                 break;
1191
1192         case RV3D_VIEW_TOP:
1193                 QUATSET(rv3d->viewquat,1.0, 0.0, 0.0, 0.0);
1194                 break;
1195
1196         case RV3D_VIEW_FRONT:
1197                 QUATSET(rv3d->viewquat,(float)cos(M_PI/4.0), (float)-sin(M_PI/4.0), 0.0, 0.0);
1198                 break;
1199
1200         case RV3D_VIEW_RIGHT:
1201                 QUATSET(rv3d->viewquat, 0.5, -0.5, -0.5, -0.5);
1202                 break;
1203         default:
1204                 return FALSE;
1205         }
1206
1207         return TRUE;
1208 }
1209
1210 /* dont set windows active in here, is used by renderwin too */
1211 void setviewmatrixview3d(Scene *scene, View3D *v3d, RegionView3D *rv3d)
1212 {
1213         if(rv3d->persp==RV3D_CAMOB) {       /* obs/camera */
1214                 if(v3d->camera) {
1215                         where_is_object(scene, v3d->camera);    
1216                         obmat_to_viewmat(v3d, rv3d, v3d->camera, 0);
1217                 }
1218                 else {
1219                         quat_to_mat4( rv3d->viewmat,rv3d->viewquat);
1220                         rv3d->viewmat[3][2]-= rv3d->dist;
1221                 }
1222         }
1223         else {
1224                 /* should be moved to better initialize later on XXX */
1225                 if(rv3d->viewlock)
1226                         ED_view3d_lock(rv3d);
1227                 
1228                 quat_to_mat4( rv3d->viewmat,rv3d->viewquat);
1229                 if(rv3d->persp==RV3D_PERSP) rv3d->viewmat[3][2]-= rv3d->dist;
1230                 if(v3d->ob_centre) {
1231                         Object *ob= v3d->ob_centre;
1232                         float vec[3];
1233                         
1234                         copy_v3_v3(vec, ob->obmat[3]);
1235                         if(ob->type==OB_ARMATURE && v3d->ob_centre_bone[0]) {
1236                                 bPoseChannel *pchan= get_pose_channel(ob->pose, v3d->ob_centre_bone);
1237                                 if(pchan) {
1238                                         copy_v3_v3(vec, pchan->pose_mat[3]);
1239                                         mul_m4_v3(ob->obmat, vec);
1240                                 }
1241                         }
1242                         translate_m4( rv3d->viewmat,-vec[0], -vec[1], -vec[2]);
1243                 }
1244                 else if (v3d->ob_centre_cursor) {
1245                         float vec[3];
1246                         copy_v3_v3(vec, give_cursor(scene, v3d));
1247                         translate_m4(rv3d->viewmat, -vec[0], -vec[1], -vec[2]);
1248                 }
1249                 else translate_m4( rv3d->viewmat,rv3d->ofs[0], rv3d->ofs[1], rv3d->ofs[2]);
1250         }
1251 }
1252
1253 /* IGLuint-> GLuint*/
1254 /* Warning: be sure to account for a negative return value
1255 *   This is an error, "Too many objects in select buffer"
1256 *   and no action should be taken (can crash blender) if this happens
1257 */
1258 short view3d_opengl_select(ViewContext *vc, unsigned int *buffer, unsigned int bufsize, rcti *input)
1259 {
1260         Scene *scene= vc->scene;
1261         View3D *v3d= vc->v3d;
1262         ARegion *ar= vc->ar;
1263         rctf rect;
1264         short code, hits;
1265         char dt, dtx;
1266         
1267         G.f |= G_PICKSEL;
1268         
1269         /* case not a border select */
1270         if(input->xmin==input->xmax) {
1271                 rect.xmin= input->xmin-12;      // seems to be default value for bones only now
1272                 rect.xmax= input->xmin+12;
1273                 rect.ymin= input->ymin-12;
1274                 rect.ymax= input->ymin+12;
1275         }
1276         else {
1277                 rect.xmin= input->xmin;
1278                 rect.xmax= input->xmax;
1279                 rect.ymin= input->ymin;
1280                 rect.ymax= input->ymax;
1281         }
1282         
1283         setwinmatrixview3d(ar, v3d, &rect);
1284         mul_m4_m4m4(vc->rv3d->persmat, vc->rv3d->viewmat, vc->rv3d->winmat);
1285         
1286         if(v3d->drawtype > OB_WIRE) {
1287                 v3d->zbuf= TRUE;
1288                 glEnable(GL_DEPTH_TEST);
1289         }
1290         
1291         if(vc->rv3d->rflag & RV3D_CLIPPING)
1292                 view3d_set_clipping(vc->rv3d);
1293         
1294         glSelectBuffer( bufsize, (GLuint *)buffer);
1295         glRenderMode(GL_SELECT);
1296         glInitNames();  /* these two calls whatfor? It doesnt work otherwise */
1297         glPushName(-1);
1298         code= 1;
1299         
1300         if(vc->obedit && vc->obedit->type==OB_MBALL) {
1301                 draw_object(scene, ar, v3d, BASACT, DRAW_PICKING|DRAW_CONSTCOLOR);
1302         }
1303         else if((vc->obedit && vc->obedit->type==OB_ARMATURE)) {
1304                 /* if not drawing sketch, draw bones */
1305                 if(!BDR_drawSketchNames(vc)) {
1306                         draw_object(scene, ar, v3d, BASACT, DRAW_PICKING|DRAW_CONSTCOLOR);
1307                 }
1308         }
1309         else {
1310                 Base *base;
1311                 
1312                 v3d->xray= TRUE;        // otherwise it postpones drawing
1313                 for(base= scene->base.first; base; base= base->next) {
1314                         if(base->lay & v3d->lay) {
1315                                 
1316                                 if (base->object->restrictflag & OB_RESTRICT_SELECT)
1317                                         base->selcol= 0;
1318                                 else {
1319                                         base->selcol= code;
1320                                         glLoadName(code);
1321                                         draw_object(scene, ar, v3d, base, DRAW_PICKING|DRAW_CONSTCOLOR);
1322                                         
1323                                         /* we draw group-duplicators for selection too */
1324                                         if((base->object->transflag & OB_DUPLI) && base->object->dup_group) {
1325                                                 ListBase *lb;
1326                                                 DupliObject *dob;
1327                                                 Base tbase;
1328                                                 
1329                                                 tbase.flag= OB_FROMDUPLI;
1330                                                 lb= object_duplilist(scene, base->object);
1331                                                 
1332                                                 for(dob= lb->first; dob; dob= dob->next) {
1333                                                         tbase.object= dob->ob;
1334                                                         copy_m4_m4(dob->ob->obmat, dob->mat);
1335                                                         
1336                                                         /* extra service: draw the duplicator in drawtype of parent */
1337                                                         /* MIN2 for the drawtype to allow bounding box objects in groups for lods */
1338                                                         dt= tbase.object->dt;   tbase.object->dt= MIN2(tbase.object->dt, base->object->dt);
1339                                                         dtx= tbase.object->dtx; tbase.object->dtx= base->object->dtx;
1340
1341                                                         draw_object(scene, ar, v3d, &tbase, DRAW_PICKING|DRAW_CONSTCOLOR);
1342                                                         
1343                                                         tbase.object->dt= dt;
1344                                                         tbase.object->dtx= dtx;
1345
1346                                                         copy_m4_m4(dob->ob->obmat, dob->omat);
1347                                                 }
1348                                                 free_object_duplilist(lb);
1349                                         }
1350                                         code++;
1351                                 }                               
1352                         }
1353                 }
1354                 v3d->xray= FALSE;       // restore
1355         }
1356         
1357         glPopName();    /* see above (pushname) */
1358         hits= glRenderMode(GL_RENDER);
1359         
1360         G.f &= ~G_PICKSEL;
1361         setwinmatrixview3d(ar, v3d, NULL);
1362         mul_m4_m4m4(vc->rv3d->persmat, vc->rv3d->viewmat, vc->rv3d->winmat);
1363         
1364         if(v3d->drawtype > OB_WIRE) {
1365                 v3d->zbuf= 0;
1366                 glDisable(GL_DEPTH_TEST);
1367         }
1368 // XXX  persp(PERSP_WIN);
1369         
1370         if(vc->rv3d->rflag & RV3D_CLIPPING)
1371                 view3d_clr_clipping();
1372         
1373         if(hits<0) printf("Too many objects in select buffer\n");       // XXX make error message
1374         
1375         return hits;
1376 }
1377
1378 /* ********************** local view operator ******************** */
1379
1380 static unsigned int free_localbit(Main *bmain)
1381 {
1382         unsigned int lay;
1383         ScrArea *sa;
1384         bScreen *sc;
1385         
1386         lay= 0;
1387         
1388         /* sometimes we loose a localview: when an area is closed */
1389         /* check all areas: which localviews are in use? */
1390         for(sc= bmain->screen.first; sc; sc= sc->id.next) {
1391                 for(sa= sc->areabase.first; sa; sa= sa->next) {
1392                         SpaceLink *sl= sa->spacedata.first;
1393                         for(; sl; sl= sl->next) {
1394                                 if(sl->spacetype==SPACE_VIEW3D) {
1395                                         View3D *v3d= (View3D*) sl;
1396                                         lay |= v3d->lay;
1397                                 }
1398                         }
1399                 }
1400         }
1401         
1402         if( (lay & 0x01000000)==0) return 0x01000000;
1403         if( (lay & 0x02000000)==0) return 0x02000000;
1404         if( (lay & 0x04000000)==0) return 0x04000000;
1405         if( (lay & 0x08000000)==0) return 0x08000000;
1406         if( (lay & 0x10000000)==0) return 0x10000000;
1407         if( (lay & 0x20000000)==0) return 0x20000000;
1408         if( (lay & 0x40000000)==0) return 0x40000000;
1409         if( (lay & 0x80000000)==0) return 0x80000000;
1410         
1411         return 0;
1412 }
1413
1414 int ED_view3d_scene_layer_set(int lay, const int *values, int *active)
1415 {
1416         int i, tot= 0;
1417         
1418         /* ensure we always have some layer selected */
1419         for(i=0; i<20; i++)
1420                 if(values[i])
1421                         tot++;
1422         
1423         if(tot==0)
1424                 return lay;
1425         
1426         for(i=0; i<20; i++) {
1427                 
1428                 if (active) {
1429                         /* if this value has just been switched on, make that layer active */
1430                         if (values[i] && (lay & (1<<i))==0) {
1431                                 *active = (1<<i);
1432                         }
1433                 }
1434                         
1435                 if (values[i]) lay |= (1<<i);
1436                 else lay &= ~(1<<i);
1437         }
1438         
1439         /* ensure always an active layer */
1440         if (active && (lay & *active)==0) {
1441                 for(i=0; i<20; i++) {
1442                         if(lay & (1<<i)) {
1443                                 *active= 1<<i;
1444                                 break;
1445                         }
1446                 }
1447         }
1448         
1449         return lay;
1450 }
1451
1452 static void initlocalview(Main *bmain, Scene *scene, ScrArea *sa)
1453 {
1454         View3D *v3d= sa->spacedata.first;
1455         Base *base;
1456         float size = 0.0, min[3], max[3], box[3];
1457         unsigned int locallay;
1458         int ok=0;
1459
1460         if(v3d->localvd) return;
1461
1462         INIT_MINMAX(min, max);
1463
1464         locallay= free_localbit(bmain);
1465
1466         if(locallay==0) {
1467                 printf("Sorry, no more than 8 localviews\n");   // XXX error 
1468                 ok= 0;
1469         }
1470         else {
1471                 if(scene->obedit) {
1472                         minmax_object(scene->obedit, min, max);
1473                         
1474                         ok= 1;
1475                 
1476                         BASACT->lay |= locallay;
1477                         scene->obedit->lay= BASACT->lay;
1478                 }
1479                 else {
1480                         for(base= FIRSTBASE; base; base= base->next) {
1481                                 if(TESTBASE(v3d, base))  {
1482                                         minmax_object(base->object, min, max);
1483                                         base->lay |= locallay;
1484                                         base->object->lay= base->lay;
1485                                         ok= 1;
1486                                 }
1487                         }
1488                 }
1489                 
1490                 box[0]= (max[0]-min[0]);
1491                 box[1]= (max[1]-min[1]);
1492                 box[2]= (max[2]-min[2]);
1493                 size= MAX3(box[0], box[1], box[2]);
1494                 if(size <= 0.01f) size= 0.01f;
1495         }
1496         
1497         if(ok) {
1498                 ARegion *ar;
1499                 
1500                 v3d->localvd= MEM_mallocN(sizeof(View3D), "localview");
1501                 
1502                 memcpy(v3d->localvd, v3d, sizeof(View3D));
1503
1504                 for(ar= sa->regionbase.first; ar; ar= ar->next) {
1505                         if(ar->regiontype == RGN_TYPE_WINDOW) {
1506                                 RegionView3D *rv3d= ar->regiondata;
1507
1508                                 rv3d->localvd= MEM_mallocN(sizeof(RegionView3D), "localview region");
1509                                 memcpy(rv3d->localvd, rv3d, sizeof(RegionView3D));
1510                                 
1511                                 rv3d->ofs[0]= -(min[0]+max[0])/2.0f;
1512                                 rv3d->ofs[1]= -(min[1]+max[1])/2.0f;
1513                                 rv3d->ofs[2]= -(min[2]+max[2])/2.0f;
1514
1515                                 rv3d->dist= size;
1516                                 /* perspective should be a bit farther away to look nice */
1517                                 if(rv3d->persp==RV3D_ORTHO)
1518                                         rv3d->dist*= 0.7f;
1519
1520                                 // correction for window aspect ratio
1521                                 if(ar->winy>2 && ar->winx>2) {
1522                                         float asp= (float)ar->winx/(float)ar->winy;
1523                                         if(asp < 1.0f) asp= 1.0f/asp;
1524                                         rv3d->dist*= asp;
1525                                 }
1526                                 
1527                                 if (rv3d->persp==RV3D_CAMOB) rv3d->persp= RV3D_PERSP;
1528                                 
1529                                 v3d->cursor[0]= -rv3d->ofs[0];
1530                                 v3d->cursor[1]= -rv3d->ofs[1];
1531                                 v3d->cursor[2]= -rv3d->ofs[2];
1532                         }
1533                 }
1534                 
1535                 v3d->lay= locallay;
1536         }
1537         else {
1538                 /* clear flags */ 
1539                 for(base= FIRSTBASE; base; base= base->next) {
1540                         if( base->lay & locallay ) {
1541                                 base->lay-= locallay;
1542                                 if(base->lay==0) base->lay= v3d->layact;
1543                                 if(base->object != scene->obedit) base->flag |= SELECT;
1544                                 base->object->lay= base->lay;
1545                         }
1546                 }               
1547         }
1548
1549 }
1550
1551 static void restore_localviewdata(ScrArea *sa, int free)
1552 {
1553         ARegion *ar;
1554         View3D *v3d= sa->spacedata.first;
1555         
1556         if(v3d->localvd==NULL) return;
1557         
1558         v3d->near= v3d->localvd->near;
1559         v3d->far= v3d->localvd->far;
1560         v3d->lay= v3d->localvd->lay;
1561         v3d->layact= v3d->localvd->layact;
1562         v3d->drawtype= v3d->localvd->drawtype;
1563         v3d->camera= v3d->localvd->camera;
1564         
1565         if(free) {
1566                 MEM_freeN(v3d->localvd);
1567                 v3d->localvd= NULL;
1568         }
1569         
1570         for(ar= sa->regionbase.first; ar; ar= ar->next) {
1571                 if(ar->regiontype == RGN_TYPE_WINDOW) {
1572                         RegionView3D *rv3d= ar->regiondata;
1573                         
1574                         if(rv3d->localvd) {
1575                                 rv3d->dist= rv3d->localvd->dist;
1576                                 copy_v3_v3(rv3d->ofs, rv3d->localvd->ofs);
1577                                 copy_qt_qt(rv3d->viewquat, rv3d->localvd->viewquat);
1578                                 rv3d->view= rv3d->localvd->view;
1579                                 rv3d->persp= rv3d->localvd->persp;
1580                                 rv3d->camzoom= rv3d->localvd->camzoom;
1581
1582                                 if(free) {
1583                                         MEM_freeN(rv3d->localvd);
1584                                         rv3d->localvd= NULL;
1585                                 }
1586                         }
1587                 }
1588         }
1589 }
1590
1591 static void endlocalview(Main *bmain, Scene *scene, ScrArea *sa)
1592 {
1593         View3D *v3d= sa->spacedata.first;
1594         struct Base *base;
1595         unsigned int locallay;
1596         
1597         if(v3d->localvd) {
1598                 
1599                 locallay= v3d->lay & 0xFF000000;
1600                 
1601                 restore_localviewdata(sa, 1); // 1 = free
1602
1603                 /* for when in other window the layers have changed */
1604                 if(v3d->scenelock) v3d->lay= scene->lay;
1605                 
1606                 for(base= FIRSTBASE; base; base= base->next) {
1607                         if( base->lay & locallay ) {
1608                                 base->lay-= locallay;
1609                                 if(base->lay==0) base->lay= v3d->layact;
1610                                 if(base->object != scene->obedit) {
1611                                         base->flag |= SELECT;
1612                                         base->object->flag |= SELECT;
1613                                 }
1614                                 base->object->lay= base->lay;
1615                         }
1616                 }
1617                 
1618                 DAG_on_visible_update(bmain, FALSE);
1619         } 
1620 }
1621
1622 static int localview_exec(bContext *C, wmOperator *UNUSED(unused))
1623 {
1624         View3D *v3d= CTX_wm_view3d(C);
1625         
1626         if(v3d->localvd)
1627                 endlocalview(CTX_data_main(C), CTX_data_scene(C), CTX_wm_area(C));
1628         else
1629                 initlocalview(CTX_data_main(C), CTX_data_scene(C), CTX_wm_area(C));
1630         
1631         ED_area_tag_redraw(CTX_wm_area(C));
1632         
1633         return OPERATOR_FINISHED;
1634 }
1635
1636 void VIEW3D_OT_localview(wmOperatorType *ot)
1637 {
1638         
1639         /* identifiers */
1640         ot->name= "Local View";
1641         ot->description= "Toggle display of selected object(s) separately and centered in view";
1642         ot->idname= "VIEW3D_OT_localview";
1643         
1644         /* api callbacks */
1645         ot->exec= localview_exec;
1646         ot->flag= OPTYPE_UNDO; /* localview changes object layer bitflags */
1647         
1648         ot->poll= ED_operator_view3d_active;
1649 }
1650
1651 #ifdef WITH_GAMEENGINE
1652
1653 static ListBase queue_back;
1654 static void SaveState(bContext *C, wmWindow *win)
1655 {
1656         Object *obact = CTX_data_active_object(C);
1657         
1658         glPushAttrib(GL_ALL_ATTRIB_BITS);
1659
1660         if(obact && obact->mode & OB_MODE_TEXTURE_PAINT)
1661                 GPU_paint_set_mipmap(1);
1662         
1663         queue_back= win->queue;
1664         
1665         win->queue.first= win->queue.last= NULL;
1666         
1667         //XXX waitcursor(1);
1668 }
1669
1670 static void RestoreState(bContext *C, wmWindow *win)
1671 {
1672         Object *obact = CTX_data_active_object(C);
1673         
1674         if(obact && obact->mode & OB_MODE_TEXTURE_PAINT)
1675                 GPU_paint_set_mipmap(0);
1676
1677         //XXX curarea->win_swap = 0;
1678         //XXX curarea->head_swap=0;
1679         //XXX allqueue(REDRAWVIEW3D, 1);
1680         //XXX allqueue(REDRAWBUTSALL, 0);
1681         //XXX reset_slowparents();
1682         //XXX waitcursor(0);
1683         //XXX G.qual= 0;
1684         
1685         if(win) /* check because closing win can set to NULL */
1686                 win->queue= queue_back;
1687         
1688         GPU_state_init();
1689         GPU_set_tpage(NULL, 0, 0);
1690
1691         glPopAttrib();
1692 }
1693
1694 /* was space_set_commmandline_options in 2.4x */
1695 static void game_set_commmandline_options(GameData *gm)
1696 {
1697         SYS_SystemHandle syshandle;
1698         int test;
1699
1700         if ( (syshandle = SYS_GetSystem()) ) {
1701                 /* User defined settings */
1702                 test= (U.gameflags & USER_DISABLE_MIPMAP);
1703                 GPU_set_mipmap(!test);
1704                 SYS_WriteCommandLineInt(syshandle, "nomipmap", test);
1705
1706                 /* File specific settings: */
1707                 /* Only test the first one. These two are switched
1708                  * simultaneously. */
1709                 test= (gm->flag & GAME_SHOW_FRAMERATE);
1710                 SYS_WriteCommandLineInt(syshandle, "show_framerate", test);
1711                 SYS_WriteCommandLineInt(syshandle, "show_profile", test);
1712
1713                 test = (gm->flag & GAME_SHOW_DEBUG_PROPS);
1714                 SYS_WriteCommandLineInt(syshandle, "show_properties", test);
1715
1716                 test= (gm->flag & GAME_SHOW_PHYSICS);
1717                 SYS_WriteCommandLineInt(syshandle, "show_physics", test);
1718
1719                 test= (gm->flag & GAME_ENABLE_ALL_FRAMES);
1720                 SYS_WriteCommandLineInt(syshandle, "fixedtime", test);
1721
1722                 test= (gm->flag & GAME_ENABLE_ANIMATION_RECORD);
1723                 SYS_WriteCommandLineInt(syshandle, "animation_record", test);
1724
1725                 test= (gm->flag & GAME_IGNORE_DEPRECATION_WARNINGS);
1726                 SYS_WriteCommandLineInt(syshandle, "ignore_deprecation_warnings", test);
1727
1728                 test= (gm->matmode == GAME_MAT_MULTITEX);
1729                 SYS_WriteCommandLineInt(syshandle, "blender_material", test);
1730                 test= (gm->matmode == GAME_MAT_GLSL);
1731                 SYS_WriteCommandLineInt(syshandle, "blender_glsl_material", test);
1732                 test= (gm->flag & GAME_DISPLAY_LISTS);
1733                 SYS_WriteCommandLineInt(syshandle, "displaylists", test);
1734
1735
1736         }
1737 }
1738
1739 #endif // WITH_GAMEENGINE
1740
1741 static int game_engine_poll(bContext *C)
1742 {
1743         /* we need a context and area to launch BGE
1744         it's a temporary solution to avoid crash at load time
1745         if we try to auto run the BGE. Ideally we want the
1746         context to be set as soon as we load the file. */
1747
1748         if(CTX_wm_window(C)==NULL) return 0;
1749         if(CTX_wm_screen(C)==NULL) return 0;
1750         if(CTX_wm_area(C)==NULL) return 0;
1751
1752         if(CTX_data_mode_enum(C)!=CTX_MODE_OBJECT)
1753                 return 0;
1754
1755         return 1;
1756 }
1757
1758 int ED_view3d_context_activate(bContext *C)
1759 {
1760         bScreen *sc= CTX_wm_screen(C);
1761         ScrArea *sa= CTX_wm_area(C);
1762         ARegion *ar;
1763
1764         /* sa can be NULL when called from python */
1765         if(sa==NULL || sa->spacetype != SPACE_VIEW3D)
1766                 for(sa=sc->areabase.first; sa; sa= sa->next)
1767                         if(sa->spacetype==SPACE_VIEW3D)
1768                                 break;
1769
1770         if(!sa)
1771                 return 0;
1772         
1773         for(ar=sa->regionbase.first; ar; ar=ar->next)
1774                 if(ar->regiontype == RGN_TYPE_WINDOW)
1775                         break;
1776         
1777         if(!ar)
1778                 return 0;
1779         
1780         // bad context switch ..
1781         CTX_wm_area_set(C, sa);
1782         CTX_wm_region_set(C, ar);
1783
1784         return 1;
1785 }
1786
1787 static int game_engine_exec(bContext *C, wmOperator *op)
1788 {
1789 #ifdef WITH_GAMEENGINE
1790         Scene *startscene = CTX_data_scene(C);
1791         ScrArea /* *sa, */ /* UNUSED */ *prevsa= CTX_wm_area(C);
1792         ARegion *ar, *prevar= CTX_wm_region(C);
1793         wmWindow *prevwin= CTX_wm_window(C);
1794         RegionView3D *rv3d;
1795         rcti cam_frame;
1796
1797         (void)op; /* unused */
1798         
1799         // bad context switch ..
1800         if(!ED_view3d_context_activate(C))
1801                 return OPERATOR_CANCELLED;
1802         
1803         rv3d= CTX_wm_region_view3d(C);
1804         /* sa= CTX_wm_area(C); */ /* UNUSED */
1805         ar= CTX_wm_region(C);
1806
1807         view3d_operator_needs_opengl(C);
1808         
1809         game_set_commmandline_options(&startscene->gm);
1810
1811         if(rv3d->persp==RV3D_CAMOB && startscene->gm.framing.type == SCE_GAMEFRAMING_BARS && startscene->gm.stereoflag != STEREO_DOME) { /* Letterbox */
1812                 rctf cam_framef;
1813                 ED_view3d_calc_camera_border(startscene, ar, CTX_wm_view3d(C), rv3d, &cam_framef, FALSE);
1814                 cam_frame.xmin = cam_framef.xmin + ar->winrct.xmin;
1815                 cam_frame.xmax = cam_framef.xmax + ar->winrct.xmin;
1816                 cam_frame.ymin = cam_framef.ymin + ar->winrct.ymin;
1817                 cam_frame.ymax = cam_framef.ymax + ar->winrct.ymin;
1818                 BLI_isect_rcti(&ar->winrct, &cam_frame, &cam_frame);
1819         }
1820         else {
1821                 cam_frame.xmin = ar->winrct.xmin;
1822                 cam_frame.xmax = ar->winrct.xmax;
1823                 cam_frame.ymin = ar->winrct.ymin;
1824                 cam_frame.ymax = ar->winrct.ymax;
1825         }
1826
1827
1828         SaveState(C, prevwin);
1829
1830         StartKetsjiShell(C, ar, &cam_frame, 1);
1831
1832         /* window wasnt closed while the BGE was running */
1833         if(BLI_findindex(&CTX_wm_manager(C)->windows, prevwin) == -1) {
1834                 prevwin= NULL;
1835                 CTX_wm_window_set(C, NULL);
1836         }
1837         
1838         if(prevwin) {
1839                 /* restore context, in case it changed in the meantime, for
1840                    example by working in another window or closing it */
1841                 CTX_wm_region_set(C, prevar);
1842                 CTX_wm_window_set(C, prevwin);
1843                 CTX_wm_area_set(C, prevsa);
1844         }
1845
1846         RestoreState(C, prevwin);
1847
1848         //XXX restore_all_scene_cfra(scene_cfra_store);
1849         set_scene_bg(CTX_data_main(C), startscene);
1850         //XXX scene_update_for_newframe(bmain, scene, scene->lay);
1851         
1852         ED_area_tag_redraw(CTX_wm_area(C));
1853
1854         return OPERATOR_FINISHED;
1855 #else
1856         (void)C; /* unused */
1857         BKE_report(op->reports, RPT_ERROR, "Game engine is disabled in this build");
1858         return OPERATOR_CANCELLED;
1859 #endif
1860 }
1861
1862 void VIEW3D_OT_game_start(wmOperatorType *ot)
1863 {
1864         
1865         /* identifiers */
1866         ot->name= "Start Game Engine";
1867         ot->description= "Start game engine";
1868         ot->idname= "VIEW3D_OT_game_start";
1869         
1870         /* api callbacks */
1871         ot->exec= game_engine_exec;
1872         
1873         ot->poll= game_engine_poll;
1874 }
1875
1876 /* ************************************** */
1877
1878 void view3d_align_axis_to_vector(View3D *v3d, RegionView3D *rv3d, int axisidx, float vec[3])
1879 {
1880         float alignaxis[3] = {0.0, 0.0, 0.0};
1881         float norm[3], axis[3], angle, new_quat[4];
1882         
1883         if(axisidx > 0) alignaxis[axisidx-1]= 1.0;
1884         else alignaxis[-axisidx-1]= -1.0;
1885
1886         normalize_v3_v3(norm, vec);
1887
1888         angle= (float)acos(dot_v3v3(alignaxis, norm));
1889         cross_v3_v3v3(axis, alignaxis, norm);
1890         axis_angle_to_quat( new_quat,axis, -angle);
1891         
1892         rv3d->view= RV3D_VIEW_USER;
1893         
1894         if (rv3d->persp==RV3D_CAMOB && v3d->camera) {
1895                 /* switch out of camera view */
1896                 float orig_ofs[3];
1897                 float orig_dist= rv3d->dist;
1898                 float orig_lens= v3d->lens;
1899                 
1900                 copy_v3_v3(orig_ofs, rv3d->ofs);
1901                 rv3d->persp= RV3D_PERSP;
1902                 rv3d->dist= 0.0;
1903                 ED_view3d_from_object(v3d->camera, rv3d->ofs, NULL, NULL, &v3d->lens);
1904                 smooth_view(NULL, NULL, NULL, NULL, NULL, orig_ofs, new_quat, &orig_dist, &orig_lens); // XXX
1905         } else {
1906                 if (rv3d->persp==RV3D_CAMOB) rv3d->persp= RV3D_PERSP; /* switch out of camera mode */
1907                 smooth_view(NULL, NULL, NULL, NULL, NULL, NULL, new_quat, NULL, NULL); // XXX
1908         }
1909 }
1910
1911 float ED_view3d_pixel_size(struct RegionView3D *rv3d, const float co[3])
1912 {
1913         return  (rv3d->persmat[3][3] + (
1914                                 rv3d->persmat[0][3]*co[0] +
1915                                 rv3d->persmat[1][3]*co[1] +
1916                                 rv3d->persmat[2][3]*co[2])
1917                         ) * rv3d->pixsize;
1918 }