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