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