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