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