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