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