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