svn merge -r39831:39877 https://svn.blender.org/svnroot/bf-blender/trunk/blender
[blender.git] / source / blender / editors / space_view3d / view3d_view.c
1 /*
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. 
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * The Original Code is Copyright (C) 2008 Blender Foundation.
21  * All rights reserved.
22  *
23  * 
24  * Contributor(s): Blender Foundation
25  *
26  * ***** END GPL LICENSE BLOCK *****
27  */
28
29 /** \file blender/editors/space_view3d/view3d_view.c
30  *  \ingroup spview3d
31  */
32
33
34 #include "DNA_camera_types.h"
35 #include "DNA_scene_types.h"
36 #include "DNA_object_types.h"
37 #include "DNA_lamp_types.h"
38
39 #include "MEM_guardedalloc.h"
40
41 #include "BLI_math.h"
42 #include "BLI_rect.h"
43 #include "BLI_listbase.h"
44 #include "BLI_utildefines.h"
45
46 #include "BKE_anim.h"
47 #include "BKE_action.h"
48 #include "BKE_context.h"
49 #include "BKE_depsgraph.h"
50 #include "BKE_object.h"
51 #include "BKE_global.h"
52 #include "BKE_main.h"
53 #include "BKE_report.h"
54 #include "BKE_scene.h"
55 #include "BKE_screen.h"
56
57 #include "BIF_gl.h"
58 #include "BIF_glutil.h"
59
60 #include "GPU_draw.h"
61
62 #include "WM_api.h"
63 #include "WM_types.h"
64
65 #include "ED_screen.h"
66 #include "ED_armature.h"
67
68 #ifdef WITH_GAMEENGINE
69 #include "BL_System.h"
70 #endif
71
72 #include "view3d_intern.h"      // own include
73
74 /* use this call when executing an operator,
75    event system doesn't set for each event the
76    opengl drawing context */
77 void view3d_operator_needs_opengl(const bContext *C)
78 {
79         wmWindow *win = CTX_wm_window(C);
80         ARegion *ar= CTX_wm_region(C);
81         
82         view3d_region_operator_needs_opengl(win, ar);
83 }
84
85 void view3d_region_operator_needs_opengl(wmWindow *win, ARegion *ar)
86 {
87         /* for debugging purpose, context should always be OK */
88         if ((ar == NULL) || (ar->regiontype!=RGN_TYPE_WINDOW))
89                 printf("view3d_region_operator_needs_opengl error, wrong region\n");
90         else {
91                 RegionView3D *rv3d= ar->regiondata;
92                 
93                 wmSubWindowSet(win, ar->swinid);
94                 glMatrixMode(GL_PROJECTION);
95                 glLoadMatrixf(rv3d->winmat);
96                 glMatrixMode(GL_MODELVIEW);
97                 glLoadMatrixf(rv3d->viewmat);
98         }
99 }
100
101 float *give_cursor(Scene *scene, View3D *v3d)
102 {
103         if(v3d && v3d->localvd) return v3d->cursor;
104         else return scene->cursor;
105 }
106
107
108 /* Gets the lens and clipping values from a camera of lamp type object */
109 void ED_view3d_ob_clip_range_get(Object *ob, float *lens, float *clipsta, float *clipend)
110 {
111         if(ob->type==OB_LAMP ) {
112                 Lamp *la = ob->data;
113                 if (lens) {
114                         float x1, fac;
115                         fac= cosf((float)M_PI*la->spotsize/360.0f);
116                         x1= saacos(fac);
117                         *lens= 16.0f*fac/sinf(x1);
118                 }
119                 if (clipsta)    *clipsta= la->clipsta;
120                 if (clipend)    *clipend= la->clipend;
121         }
122         else if(ob->type==OB_CAMERA) {
123                 Camera *cam= ob->data;
124                 if (lens)               *lens= cam->lens;
125                 if (clipsta)    *clipsta= cam->clipsta;
126                 if (clipend)    *clipend= cam->clipend;
127         }
128         else {
129                 if (lens)               *lens= 35.0f;
130         }
131 }
132
133 /* ****************** smooth view operator ****************** */
134 /* This operator is one of the 'timer refresh' ones like animation playback */
135
136 struct SmoothViewStore {
137         float orig_dist, new_dist;
138         float orig_lens, new_lens;
139         float orig_quat[4], new_quat[4];
140         float orig_ofs[3], new_ofs[3];
141         
142         int to_camera, orig_view;
143         
144         double time_allowed;
145 };
146
147 /* will start timer if appropriate */
148 /* the arguments are the desired situation */
149 void smooth_view(bContext *C, View3D *v3d, ARegion *ar, Object *oldcamera, Object *camera, float *ofs, float *quat, float *dist, float *lens)
150 {
151         wmWindowManager *wm= CTX_wm_manager(C);
152         wmWindow *win= CTX_wm_window(C);
153         ScrArea *sa= CTX_wm_area(C);
154
155         RegionView3D *rv3d= ar->regiondata;
156         struct SmoothViewStore sms= {0};
157         short ok= FALSE;
158         
159         /* initialize sms */
160         copy_v3_v3(sms.new_ofs, rv3d->ofs);
161         copy_qt_qt(sms.new_quat, rv3d->viewquat);
162         sms.new_dist= rv3d->dist;
163         sms.new_lens= v3d->lens;
164         sms.to_camera= 0;
165
166         /* note on camera locking, this is a little confusing but works ok.
167          * we may be changing the view 'as if' there is no active camera, but infact
168          * there is an active camera which is locked to the view.
169          *
170          * In the case where smooth view is moving _to_ a camera we dont want that
171          * camera to be moved or changed, so only when the camera is not being set should
172          * we allow camera option locking to initialize the view settings from the camera.
173          */
174         if(camera == NULL && oldcamera == NULL) {
175                 ED_view3d_camera_lock_init(v3d, rv3d);
176         }
177
178         /* store the options we want to end with */
179         if(ofs) copy_v3_v3(sms.new_ofs, ofs);
180         if(quat) copy_qt_qt(sms.new_quat, quat);
181         if(dist) sms.new_dist= *dist;
182         if(lens) sms.new_lens= *lens;
183
184         if (camera) {
185                 ED_view3d_from_object(camera, sms.new_ofs, sms.new_quat, &sms.new_dist, &sms.new_lens);
186                 sms.to_camera= 1; /* restore view3d values in end */
187         }
188         
189         if (C && U.smooth_viewtx) {
190                 int changed = 0; /* zero means no difference */
191                 
192                 if (oldcamera != camera)
193                         changed = 1;
194                 else if (sms.new_dist != rv3d->dist)
195                         changed = 1;
196                 else if (sms.new_lens != v3d->lens)
197                         changed = 1;
198                 else if (!equals_v3v3(sms.new_ofs, rv3d->ofs))
199                         changed = 1;
200                 else if (!equals_v4v4(sms.new_quat, rv3d->viewquat))
201                         changed = 1;
202                 
203                 /* The new view is different from the old one
204                         * so animate the view */
205                 if (changed) {
206
207                         /* original values */
208                         if (oldcamera) {
209                                 sms.orig_dist= rv3d->dist; // below function does weird stuff with it...
210                                 ED_view3d_from_object(oldcamera, sms.orig_ofs, sms.orig_quat, &sms.orig_dist, &sms.orig_lens);
211                         }
212                         else {
213                                 copy_v3_v3(sms.orig_ofs, rv3d->ofs);
214                                 copy_qt_qt(sms.orig_quat, rv3d->viewquat);
215                                 sms.orig_dist= rv3d->dist;
216                                 sms.orig_lens= v3d->lens;
217                         }
218                         /* grid draw as floor */
219                         if((rv3d->viewlock & RV3D_LOCKED)==0) {
220                                 /* use existing if exists, means multiple calls to smooth view wont loose the original 'view' setting */
221                                 sms.orig_view= rv3d->sms ? rv3d->sms->orig_view : rv3d->view;
222                                 rv3d->view= RV3D_VIEW_USER;
223                         }
224
225                         sms.time_allowed= (double)U.smooth_viewtx / 1000.0;
226                         
227                         /* if this is view rotation only
228                                 * we can decrease the time allowed by
229                                 * the angle between quats 
230                                 * this means small rotations wont lag */
231                         if (quat && !ofs && !dist) {
232                                 float vec1[3]={0,0,1}, vec2[3]= {0,0,1};
233                                 float q1[4], q2[4];
234
235                                 invert_qt_qt(q1, sms.new_quat);
236                                 invert_qt_qt(q2, sms.orig_quat);
237
238                                 mul_qt_v3(q1, vec1);
239                                 mul_qt_v3(q2, vec2);
240
241                                 /* scale the time allowed by the rotation */
242                                 sms.time_allowed *= (double)angle_v3v3(vec1, vec2) / M_PI; /* 180deg == 1.0 */
243                         }
244
245                         /* ensure it shows correct */
246                         if(sms.to_camera) rv3d->persp= RV3D_PERSP;
247
248                         rv3d->rflag |= RV3D_NAVIGATING;
249                         
250                         /* keep track of running timer! */
251                         if(rv3d->sms==NULL)
252                                 rv3d->sms= MEM_mallocN(sizeof(struct SmoothViewStore), "smoothview v3d");
253                         *rv3d->sms= sms;
254                         if(rv3d->smooth_timer)
255                                 WM_event_remove_timer(wm, win, rv3d->smooth_timer);
256                         /* TIMER1 is hardcoded in keymap */
257                         rv3d->smooth_timer= WM_event_add_timer(wm, win, TIMER1, 1.0/100.0);     /* max 30 frs/sec */
258                         
259                         ok= TRUE;
260                 }
261         }
262         
263         /* if we get here nothing happens */
264         if(ok == FALSE) {
265                 if(sms.to_camera==0) {
266                         copy_v3_v3(rv3d->ofs, sms.new_ofs);
267                         copy_qt_qt(rv3d->viewquat, sms.new_quat);
268                         rv3d->dist = sms.new_dist;
269                         v3d->lens = sms.new_lens;
270                 }
271
272                 if(rv3d->viewlock & RV3D_BOXVIEW)
273                         view3d_boxview_copy(sa, ar);
274
275                 ED_region_tag_redraw(ar);
276         }
277 }
278
279 /* only meant for timer usage */
280 static int view3d_smoothview_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *event)
281 {
282         View3D *v3d = CTX_wm_view3d(C);
283         RegionView3D *rv3d= CTX_wm_region_view3d(C);
284         struct SmoothViewStore *sms= rv3d->sms;
285         float step, step_inv;
286         
287         /* escape if not our timer */
288         if(rv3d->smooth_timer==NULL || rv3d->smooth_timer!=event->customdata)
289                 return OPERATOR_PASS_THROUGH;
290         
291         if(sms->time_allowed != 0.0)
292                 step = (float)((rv3d->smooth_timer->duration)/sms->time_allowed);
293         else
294                 step = 1.0f;
295         
296         /* end timer */
297         if(step >= 1.0f) {
298                 
299                 /* if we went to camera, store the original */
300                 if(sms->to_camera) {
301                         rv3d->persp= RV3D_CAMOB;
302                         copy_v3_v3(rv3d->ofs, sms->orig_ofs);
303                         copy_qt_qt(rv3d->viewquat, sms->orig_quat);
304                         rv3d->dist = sms->orig_dist;
305                         v3d->lens = sms->orig_lens;
306                 }
307                 else {
308                         copy_v3_v3(rv3d->ofs, sms->new_ofs);
309                         copy_qt_qt(rv3d->viewquat, sms->new_quat);
310                         rv3d->dist = sms->new_dist;
311                         v3d->lens = sms->new_lens;
312
313                         ED_view3d_camera_lock_sync(v3d, rv3d);
314                 }
315                 
316                 if((rv3d->viewlock & RV3D_LOCKED)==0) {
317                         rv3d->view= sms->orig_view;
318                 }
319
320                 MEM_freeN(rv3d->sms);
321                 rv3d->sms= NULL;
322                 
323                 WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), rv3d->smooth_timer);
324                 rv3d->smooth_timer= NULL;
325                 rv3d->rflag &= ~RV3D_NAVIGATING;
326         }
327         else {
328                 int i;
329                 
330                 /* ease in/out */
331                 if (step < 0.5f)        step = (float)pow(step*2.0f, 2.0)/2.0f;
332                 else                            step = (float)1.0f-(powf(2.0f*(1.0f-step),2.0f)/2.0f);
333
334                 step_inv = 1.0f-step;
335
336                 for (i=0; i<3; i++)
337                         rv3d->ofs[i] = sms->new_ofs[i] * step + sms->orig_ofs[i]*step_inv;
338
339                 interp_qt_qtqt(rv3d->viewquat, sms->orig_quat, sms->new_quat, step);
340                 
341                 rv3d->dist = sms->new_dist * step + sms->orig_dist*step_inv;
342                 v3d->lens = sms->new_lens * step + sms->orig_lens*step_inv;
343
344                 ED_view3d_camera_lock_sync(v3d, rv3d);
345         }
346         
347         if(rv3d->viewlock & RV3D_BOXVIEW)
348                 view3d_boxview_copy(CTX_wm_area(C), CTX_wm_region(C));
349         
350         WM_event_add_notifier(C, NC_SPACE|ND_SPACE_VIEW3D, v3d);
351         
352         return OPERATOR_FINISHED;
353 }
354
355 void VIEW3D_OT_smoothview(wmOperatorType *ot)
356 {
357         
358         /* identifiers */
359         ot->name= "Smooth View";
360         ot->idname= "VIEW3D_OT_smoothview";
361         ot->description="The time to animate the change of view (in milliseconds)";
362         
363         /* api callbacks */
364         ot->invoke= view3d_smoothview_invoke;
365         
366         ot->poll= ED_operator_view3d_active;
367 }
368
369 /* ****************** change view operators ****************** */
370
371 static int view3d_setcameratoview_exec(bContext *C, wmOperator *UNUSED(op))
372 {
373         View3D *v3d = CTX_wm_view3d(C);
374         RegionView3D *rv3d= CTX_wm_region_view3d(C);
375
376         copy_qt_qt(rv3d->lviewquat, rv3d->viewquat);
377         rv3d->lview= rv3d->view;
378         if(rv3d->persp != RV3D_CAMOB) {
379                 rv3d->lpersp= rv3d->persp;
380         }
381
382         ED_view3d_to_object(v3d->camera, rv3d->ofs, rv3d->viewquat, rv3d->dist);
383         DAG_id_tag_update(&v3d->camera->id, OB_RECALC_OB);
384         rv3d->persp = RV3D_CAMOB;
385         
386         WM_event_add_notifier(C, NC_OBJECT|ND_TRANSFORM, v3d->camera);
387         
388         return OPERATOR_FINISHED;
389
390 }
391
392 static int view3d_setcameratoview_poll(bContext *C)
393 {
394         View3D *v3d= CTX_wm_view3d(C);
395         if(v3d && v3d->camera && v3d->camera->id.lib==NULL) {
396                 RegionView3D *rv3d= CTX_wm_region_view3d(C);
397                 if(rv3d && !rv3d->viewlock) {
398                         return 1;
399                 }
400         }
401
402         return 0;
403 }
404
405 void VIEW3D_OT_setcameratoview(wmOperatorType *ot)
406 {
407         
408         /* identifiers */
409         ot->name= "Align Camera To View";
410         ot->description= "Set camera view to active view";
411         ot->idname= "VIEW3D_OT_camera_to_view";
412         
413         /* api callbacks */
414         ot->exec= view3d_setcameratoview_exec;  
415         ot->poll= view3d_setcameratoview_poll;
416         
417         /* flags */
418         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
419 }
420
421
422 static int view3d_setobjectascamera_exec(bContext *C, wmOperator *UNUSED(op))
423 {
424         View3D *v3d = CTX_wm_view3d(C);
425         ARegion *ar= ED_view3d_context_region_unlock(C);
426         RegionView3D *rv3d= ar->regiondata; /* no NULL check is needed, poll checks */
427         Scene *scene= CTX_data_scene(C);
428         Object *ob = CTX_data_active_object(C);
429
430         if(ob) {
431                 Object *camera_old= (rv3d->persp == RV3D_CAMOB) ? V3D_CAMERA_SCENE(scene, v3d) : NULL;
432                 rv3d->persp= RV3D_CAMOB;
433                 v3d->camera= ob;
434                 if(v3d->scenelock)
435                         scene->camera= ob;
436
437                 if(camera_old != ob) /* unlikely but looks like a glitch when set to the same */
438                         smooth_view(C, v3d, ar, camera_old, v3d->camera, rv3d->ofs, rv3d->viewquat, &rv3d->dist, &v3d->lens);
439
440                 WM_event_add_notifier(C, NC_SCENE|ND_RENDER_OPTIONS|NC_OBJECT|ND_DRAW, CTX_data_scene(C));
441         }
442         
443         return OPERATOR_FINISHED;
444 }
445
446 int ED_operator_rv3d_unlock_poll(bContext *C)
447 {
448         return ED_view3d_context_region_unlock(C) != NULL;
449 }
450
451 void VIEW3D_OT_object_as_camera(wmOperatorType *ot)
452 {
453         
454         /* identifiers */
455         ot->name= "Set Active Object as Camera";
456         ot->description= "Set the active object as the active camera for this view or scene";
457         ot->idname= "VIEW3D_OT_object_as_camera";
458         
459         /* api callbacks */
460         ot->exec= view3d_setobjectascamera_exec;        
461         ot->poll= ED_operator_rv3d_unlock_poll;
462         
463         /* flags */
464         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
465 }
466
467 /* ********************************** */
468
469 void ED_view3d_calc_clipping(BoundBox *bb, float planes[4][4], bglMats *mats, rcti *rect)
470 {
471         float modelview[4][4];
472         double xs, ys, p[3];
473         int val, flip_sign, a;
474
475         /* near zero floating point values can give issues with gluUnProject
476                 in side view on some implementations */
477         if(fabs(mats->modelview[0]) < 1e-6) mats->modelview[0]= 0.0;
478         if(fabs(mats->modelview[5]) < 1e-6) mats->modelview[5]= 0.0;
479
480         /* Set up viewport so that gluUnProject will give correct values */
481         mats->viewport[0] = 0;
482         mats->viewport[1] = 0;
483
484         /* four clipping planes and bounding volume */
485         /* first do the bounding volume */
486         for(val=0; val<4; val++) {
487                 xs= (val==0||val==3)?rect->xmin:rect->xmax;
488                 ys= (val==0||val==1)?rect->ymin:rect->ymax;
489
490                 gluUnProject(xs, ys, 0.0, mats->modelview, mats->projection, mats->viewport, &p[0], &p[1], &p[2]);
491                 VECCOPY(bb->vec[val], p);
492
493                 gluUnProject(xs, ys, 1.0, mats->modelview, mats->projection, mats->viewport, &p[0], &p[1], &p[2]);
494                 VECCOPY(bb->vec[4+val], p);
495         }
496
497         /* verify if we have negative scale. doing the transform before cross
498            product flips the sign of the vector compared to doing cross product
499            before transform then, so we correct for that. */
500         for(a=0; a<16; a++)
501                 ((float*)modelview)[a] = mats->modelview[a];
502         flip_sign = is_negative_m4(modelview);
503
504         /* then plane equations */
505         for(val=0; val<4; val++) {
506
507                 normal_tri_v3(planes[val], bb->vec[val], bb->vec[val==3?0:val+1], bb->vec[val+4]);
508
509                 if(flip_sign)
510                         negate_v3(planes[val]);
511
512                 planes[val][3]= - planes[val][0]*bb->vec[val][0]
513                         - planes[val][1]*bb->vec[val][1]
514                         - planes[val][2]*bb->vec[val][2];
515         }
516 }
517
518 /* create intersection coordinates in view Z direction at mouse coordinates */
519 void ED_view3d_win_to_segment_clip(ARegion *ar, View3D *v3d, const float mval[2], float ray_start[3], float ray_end[3])
520 {
521         RegionView3D *rv3d= ar->regiondata;
522         
523         if(rv3d->is_persp) {
524                 float vec[3];
525                 ED_view3d_win_to_vector(ar, mval, vec);
526
527                 copy_v3_v3(ray_start, rv3d->viewinv[3]);
528                 VECADDFAC(ray_start, rv3d->viewinv[3], vec, v3d->near);
529                 VECADDFAC(ray_end, rv3d->viewinv[3], vec, v3d->far);
530         }
531         else {
532                 float vec[4];
533                 vec[0] = 2.0f * mval[0] / ar->winx - 1;
534                 vec[1] = 2.0f * mval[1] / ar->winy - 1;
535                 vec[2] = 0.0f;
536                 vec[3] = 1.0f;
537                 
538                 mul_m4_v4(rv3d->persinv, vec);
539                 
540                 VECADDFAC(ray_start, vec, rv3d->viewinv[2],  1000.0f);
541                 VECADDFAC(ray_end, vec, rv3d->viewinv[2], -1000.0f);
542         }
543
544         /* clipping */
545         if(rv3d->rflag & RV3D_CLIPPING) {
546                 int a;
547                 for(a=0; a<4; a++) {
548                         clip_line_plane(ray_start, ray_end, rv3d->clip[a]);
549                 }
550         }
551 }
552
553 /* create intersection ray in view Z direction at mouse coordinates */
554 void ED_view3d_win_to_ray(ARegion *ar, View3D *v3d, const float mval[2], float ray_start[3], float ray_normal[3])
555 {
556         float ray_end[3];
557         
558         ED_view3d_win_to_segment_clip(ar, v3d, mval, ray_start, ray_end);
559         sub_v3_v3v3(ray_normal, ray_end, ray_start);
560         normalize_v3(ray_normal);
561 }
562
563 void ED_view3d_global_to_vector(RegionView3D *rv3d, const float coord[3], float vec[3])
564 {
565         if (rv3d->is_persp) {
566                 float p1[4], p2[4];
567
568                 copy_v3_v3(p1, coord);
569                 p1[3] = 1.0f;
570                 copy_v3_v3(p2, p1);
571                 p2[3] = 1.0f;
572                 mul_m4_v4(rv3d->viewmat, p2);
573
574                 mul_v3_fl(p2, 2.0f);
575
576                 mul_m4_v4(rv3d->viewinv, p2);
577
578                 sub_v3_v3v3(vec, p1, p2);
579         }
580         else {
581                 copy_v3_v3(vec, rv3d->viewinv[2]);
582         }
583         normalize_v3(vec);
584 }
585
586 int initgrabz(RegionView3D *rv3d, float x, float y, float z)
587 {
588         int flip= FALSE;
589         if(rv3d==NULL) return flip;
590         rv3d->zfac= rv3d->persmat[0][3]*x+ rv3d->persmat[1][3]*y+ rv3d->persmat[2][3]*z+ rv3d->persmat[3][3];
591         if (rv3d->zfac < 0.0f)
592                 flip= TRUE;
593         /* if x,y,z is exactly the viewport offset, zfac is 0 and we don't want that 
594                 * (accounting for near zero values)
595                 * */
596         if (rv3d->zfac < 1.e-6f && rv3d->zfac > -1.e-6f) rv3d->zfac = 1.0f;
597         
598         /* Negative zfac means x, y, z was behind the camera (in perspective).
599                 * This gives flipped directions, so revert back to ok default case.
600         */
601         // NOTE: I've changed this to flip zfac to be positive again for now so that GPencil draws ok
602         //      -- Aligorith, 2009Aug31
603         //if (rv3d->zfac < 0.0f) rv3d->zfac = 1.0f;
604         if (rv3d->zfac < 0.0f) rv3d->zfac= -rv3d->zfac;
605         
606         return flip;
607 }
608
609 void ED_view3d_win_to_3d(ARegion *ar, const float depth_pt[3], const float mval[2], float out[3])
610 {
611         RegionView3D *rv3d= ar->regiondata;
612         
613         float line_sta[3];
614         float line_end[3];
615
616         if(rv3d->is_persp) {
617                 float mousevec[3];
618                 copy_v3_v3(line_sta, rv3d->viewinv[3]);
619                 ED_view3d_win_to_vector(ar, mval, mousevec);
620                 add_v3_v3v3(line_end, line_sta, mousevec);
621
622                 if(isect_line_plane_v3(out, line_sta, line_end, depth_pt, rv3d->viewinv[2], TRUE) == 0) {
623                         /* highly unlikely to ever happen, mouse vec paralelle with view plane */
624                         zero_v3(out);
625                 }
626         }
627         else {
628                 const float dx= (2.0f * mval[0] / (float)ar->winx) - 1.0f;
629                 const float dy= (2.0f * mval[1] / (float)ar->winy) - 1.0f;
630                 line_sta[0]= (rv3d->persinv[0][0] * dx) + (rv3d->persinv[1][0] * dy) + rv3d->viewinv[3][0];
631                 line_sta[1]= (rv3d->persinv[0][1] * dx) + (rv3d->persinv[1][1] * dy) + rv3d->viewinv[3][1];
632                 line_sta[2]= (rv3d->persinv[0][2] * dx) + (rv3d->persinv[1][2] * dy) + rv3d->viewinv[3][2];
633
634                 add_v3_v3v3(line_end, line_sta, rv3d->viewinv[2]);
635                 closest_to_line_v3(out, depth_pt, line_sta, line_end);
636         }
637 }
638
639 /* always call initgrabz */
640 /* only to detect delta motion */
641 void ED_view3d_win_to_delta(ARegion *ar, const float mval[2], float out[3])
642 {
643         RegionView3D *rv3d= ar->regiondata;
644         float dx, dy;
645         
646         dx= 2.0f*mval[0]*rv3d->zfac/ar->winx;
647         dy= 2.0f*mval[1]*rv3d->zfac/ar->winy;
648         
649         out[0]= (rv3d->persinv[0][0]*dx + rv3d->persinv[1][0]*dy);
650         out[1]= (rv3d->persinv[0][1]*dx + rv3d->persinv[1][1]*dy);
651         out[2]= (rv3d->persinv[0][2]*dx + rv3d->persinv[1][2]*dy);
652 }
653
654 /* doesn't rely on initgrabz */
655 /* for perspective view, get the vector direction to
656  * the mouse cursor as a normalized vector */
657 void ED_view3d_win_to_vector(ARegion *ar, const float mval[2], float out[3])
658 {
659         RegionView3D *rv3d= ar->regiondata;
660
661         if(rv3d->is_persp) {
662                 out[0]= 2.0f * (mval[0] / ar->winx) - 1.0f;
663                 out[1]= 2.0f * (mval[1] / ar->winy) - 1.0f;
664                 out[2]= -0.5f;
665                 mul_project_m4_v3(rv3d->persinv, out);
666                 sub_v3_v3(out, rv3d->viewinv[3]);
667         }
668         else {
669                 copy_v3_v3(out, rv3d->viewinv[2]);
670         }
671         normalize_v3(out);
672 }
673
674 float ED_view3d_depth_read_cached(ViewContext *vc, int x, int y)
675 {
676         ViewDepths *vd = vc->rv3d->depths;
677                 
678         x -= vc->ar->winrct.xmin;
679         y -= vc->ar->winrct.ymin;
680
681         if(vd && vd->depths && x > 0 && y > 0 && x < vd->w && y < vd->h)
682                 return vd->depths[y * vd->w + x];
683         else
684                 return 1;
685 }
686
687 void ED_view3d_depth_tag_update(RegionView3D *rv3d)
688 {
689         if(rv3d->depths)
690                 rv3d->depths->damaged= 1;
691 }
692
693 void ED_view3d_ob_project_mat_get(RegionView3D *rv3d, Object *ob, float pmat[4][4])
694 {
695         float vmat[4][4];
696         
697         mul_m4_m4m4(vmat, ob->obmat, rv3d->viewmat);
698         mul_m4_m4m4(pmat, vmat, rv3d->winmat);
699 }
700
701 /* Uses window coordinates (x,y) and depth component z to find a point in
702    modelspace */
703 void view3d_unproject(bglMats *mats, float out[3], const short x, const short y, const float z)
704 {
705         double ux, uy, uz;
706
707                 gluUnProject(x,y,z, mats->modelview, mats->projection,
708                          (GLint *)mats->viewport, &ux, &uy, &uz );
709         out[0] = ux;
710         out[1] = uy;
711         out[2] = uz;
712 }
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         VECCOPY(vec4, vec);
720         adr[0]= IS_CLIPPED;
721         copy_v3_v3(vec4, vec);
722         vec4[3]= 1.0;
723         
724         mul_m4_v4(mat, vec4);
725         
726         if( vec4[3]>FLT_EPSILON ) {
727                 adr[0] = (float)(ar->winx/2.0f)+(ar->winx/2.0f)*vec4[0]/vec4[3];        
728                 adr[1] = (float)(ar->winy/2.0f)+(ar->winy/2.0f)*vec4[1]/vec4[3];
729         } else {
730                 adr[0] = adr[1] = 0.0f;
731         }
732 }
733
734 /* use view3d_get_object_project_mat to get projecting mat */
735 void ED_view3d_project_float_v3(ARegion *ar, float *vec, float *adr, float mat[4][4])
736 {
737         float vec4[4];
738         
739         VECCOPY(vec4, vec);
740         adr[0]= IS_CLIPPED;
741         vec4[3]= 1.0;
742         
743         mul_m4_v4(mat, vec4);
744         
745         if( vec4[3]>FLT_EPSILON ) {
746                 adr[0] = (float)(ar->winx/2.0f)+(ar->winx/2.0f)*vec4[0]/vec4[3];        
747                 adr[1] = (float)(ar->winy/2.0f)+(ar->winy/2.0f)*vec4[1]/vec4[3];
748                 adr[2] = vec4[2]/vec4[3];
749         } else {
750                 adr[0] = adr[1] = adr[2] = 0.0f;
751         }
752 }
753
754 int ED_view3d_boundbox_clip(RegionView3D *rv3d, float obmat[][4], BoundBox *bb)
755 {
756         /* return 1: draw */
757         
758         float mat[4][4];
759         float vec[4], min, max;
760         int a, flag= -1, fl;
761         
762         if(bb==NULL) return 1;
763         if(bb->flag & OB_BB_DISABLED) return 1;
764         
765         mul_m4_m4m4(mat, obmat, rv3d->persmat);
766         
767         for(a=0; a<8; a++) {
768                 copy_v3_v3(vec, bb->vec[a]);
769                 vec[3]= 1.0;
770                 mul_m4_v4(mat, vec);
771                 max= vec[3];
772                 min= -vec[3];
773                 
774                 fl= 0;
775                 if(vec[0] < min) fl+= 1;
776                 if(vec[0] > max) fl+= 2;
777                 if(vec[1] < min) fl+= 4;
778                 if(vec[1] > max) fl+= 8;
779                 if(vec[2] < min) fl+= 16;
780                 if(vec[2] > max) fl+= 32;
781                 
782                 flag &= fl;
783                 if(flag==0) return 1;
784         }
785         
786         return 0;
787 }
788
789 void project_short(ARegion *ar, const float vec[3], short adr[2])       /* clips */
790 {
791         RegionView3D *rv3d= ar->regiondata;
792         float fx, fy, vec4[4];
793         
794         adr[0]= IS_CLIPPED;
795         
796         if(rv3d->rflag & RV3D_CLIPPING) {
797                 if(ED_view3d_test_clipping(rv3d, vec, 0))
798                         return;
799         }
800         
801         copy_v3_v3(vec4, vec);
802         vec4[3]= 1.0;
803         mul_m4_v4(rv3d->persmat, vec4);
804         
805         if( vec4[3] > (float)BL_NEAR_CLIP ) {   /* 0.001 is the NEAR clipping cutoff for picking */
806                 fx= (ar->winx/2)*(1 + vec4[0]/vec4[3]);
807                 
808                 if( fx>0 && fx<ar->winx) {
809                         
810                         fy= (ar->winy/2)*(1 + vec4[1]/vec4[3]);
811                         
812                         if(fy > 0.0f && fy < (float)ar->winy) {
813                                 adr[0]= (short)floor(fx); 
814                                 adr[1]= (short)floor(fy);
815                         }
816                 }
817         }
818 }
819
820 void project_int(ARegion *ar, const float vec[3], int adr[2])
821 {
822         RegionView3D *rv3d= ar->regiondata;
823         float fx, fy, vec4[4];
824         
825         adr[0]= (int)2140000000.0f;
826         copy_v3_v3(vec4, vec);
827         vec4[3]= 1.0;
828         
829         mul_m4_v4(rv3d->persmat, vec4);
830         
831         if( vec4[3] > (float)BL_NEAR_CLIP ) {   /* 0.001 is the NEAR clipping cutoff for picking */
832                 fx= (ar->winx/2)*(1 + vec4[0]/vec4[3]);
833                 
834                 if( fx>-2140000000.0f && fx<2140000000.0f) {
835                         fy= (ar->winy/2)*(1 + vec4[1]/vec4[3]);
836                         
837                         if(fy>-2140000000.0f && fy<2140000000.0f) {
838                                 adr[0]= (int)floor(fx); 
839                                 adr[1]= (int)floor(fy);
840                         }
841                 }
842         }
843 }
844
845 void project_int_noclip(ARegion *ar, const float vec[3], int adr[2])
846 {
847         RegionView3D *rv3d= ar->regiondata;
848         float fx, fy, vec4[4];
849         
850         copy_v3_v3(vec4, vec);
851         vec4[3]= 1.0;
852         
853         mul_m4_v4(rv3d->persmat, vec4);
854         
855         if( fabs(vec4[3]) > BL_NEAR_CLIP ) {
856                 fx = (ar->winx/2)*(1 + vec4[0]/vec4[3]);
857                 fy = (ar->winy/2)*(1 + vec4[1]/vec4[3]);
858                 
859                 adr[0] = (int)floor(fx); 
860                 adr[1] = (int)floor(fy);
861         }
862         else {
863                 adr[0] = ar->winx / 2;
864                 adr[1] = ar->winy / 2;
865         }
866 }
867
868 void project_short_noclip(ARegion *ar, const float vec[3], short adr[2])
869 {
870         RegionView3D *rv3d= ar->regiondata;
871         float fx, fy, vec4[4];
872         
873         adr[0]= IS_CLIPPED;
874         copy_v3_v3(vec4, vec);
875         vec4[3]= 1.0;
876         
877         mul_m4_v4(rv3d->persmat, vec4);
878         
879         if( vec4[3] > (float)BL_NEAR_CLIP ) {   /* 0.001 is the NEAR clipping cutoff for picking */
880                 fx= (ar->winx/2)*(1 + vec4[0]/vec4[3]);
881                 
882                 if( fx>-32700 && fx<32700) {
883                         
884                         fy= (ar->winy/2)*(1 + vec4[1]/vec4[3]);
885                         
886                         if(fy > -32700.0f && fy < 32700.0f) {
887                                 adr[0]= (short)floor(fx); 
888                                 adr[1]= (short)floor(fy);
889                         }
890                 }
891         }
892 }
893
894 void project_float(ARegion *ar, const float vec[3], float adr[2])
895 {
896         RegionView3D *rv3d= ar->regiondata;
897         float vec4[4];
898         
899         adr[0]= IS_CLIPPED;
900         copy_v3_v3(vec4, vec);
901         vec4[3]= 1.0;
902         
903         mul_m4_v4(rv3d->persmat, vec4);
904         
905         if(vec4[3] > (float)BL_NEAR_CLIP) {
906                 adr[0] = (float)(ar->winx/2.0f)+(ar->winx/2.0f)*vec4[0]/vec4[3];
907                 adr[1] = (float)(ar->winy/2.0f)+(ar->winy/2.0f)*vec4[1]/vec4[3];
908         }
909 }
910
911 void project_float_noclip(ARegion *ar, const float vec[3], float adr[2])
912 {
913         RegionView3D *rv3d= ar->regiondata;
914         float vec4[4];
915         
916         copy_v3_v3(vec4, vec);
917         vec4[3]= 1.0;
918         
919         mul_m4_v4(rv3d->persmat, vec4);
920         
921         if( fabs(vec4[3]) > BL_NEAR_CLIP ) {
922                 adr[0] = (float)(ar->winx/2.0f)+(ar->winx/2.0f)*vec4[0]/vec4[3];
923                 adr[1] = (float)(ar->winy/2.0f)+(ar->winy/2.0f)*vec4[1]/vec4[3];
924         }
925         else {
926                 adr[0] = ar->winx / 2.0f;
927                 adr[1] = ar->winy / 2.0f;
928         }
929 }
930
931 /* copies logic of get_view3d_viewplane(), keep in sync */
932 int ED_view3d_clip_range_get(View3D *v3d, RegionView3D *rv3d, float *clipsta, float *clipend)
933 {
934         int orth= 0;
935
936         *clipsta= v3d->near;
937         *clipend= v3d->far;
938
939         if(rv3d->persp==RV3D_CAMOB) {
940                 if(v3d->camera) {
941                         if(v3d->camera->type==OB_LAMP ) {
942                                 Lamp *la= v3d->camera->data;
943                                 *clipsta= la->clipsta;
944                                 *clipend= la->clipend;
945                         }
946                         else if(v3d->camera->type==OB_CAMERA) {
947                                 Camera *cam= v3d->camera->data;
948                                 *clipsta= cam->clipsta;
949                                 *clipend= cam->clipend;
950
951                                 if(cam->type==CAM_ORTHO)
952                                         orth= 1;
953                         }
954                 }
955         }
956
957         if(rv3d->persp==RV3D_ORTHO) {
958                 *clipend *= 0.5f;       // otherwise too extreme low zbuffer quality
959                 *clipsta= - *clipend;
960                 orth= 1;
961         }
962
963         return orth;
964 }
965
966 /* also exposed in previewrender.c */
967 int ED_view3d_viewplane_get(View3D *v3d, RegionView3D *rv3d, int winxi, int winyi, rctf *viewplane, float *clipsta, float *clipend, float *pixsize)
968 {
969         Camera *cam=NULL;
970         float lens, fac, x1, y1, x2, y2;
971         float winx= (float)winxi, winy= (float)winyi;
972         int orth= 0;
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                                 *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= 64.0f/(fac*winx*lens);
1042                         else dfac= 64.0f/(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) * 32.0f;
1062                                 dy += cam->shifty * (cam->clipsta / cam->lens) * 32.0f;
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);
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, *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);
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, rv3d, CTX_wm_view3d(C), &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 }