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