2.5
[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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, 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 #include <string.h>
30 #include <stdio.h>
31 #include <math.h>
32 #include <float.h>
33
34 #include "DNA_action_types.h"
35 #include "DNA_armature_types.h"
36 #include "DNA_camera_types.h"
37 #include "DNA_lamp_types.h"
38 #include "DNA_object_types.h"
39 #include "DNA_space_types.h"
40 #include "DNA_scene_types.h"
41 #include "DNA_screen_types.h"
42 #include "DNA_userdef_types.h"
43 #include "DNA_view3d_types.h"
44 #include "DNA_world_types.h"
45
46 #include "MEM_guardedalloc.h"
47
48 #include "BLI_blenlib.h"
49 #include "BLI_arithb.h"
50 #include "BLI_rand.h"
51
52 #include "BKE_anim.h"
53 #include "BKE_action.h"
54 #include "BKE_context.h"
55 #include "BKE_object.h"
56 #include "BKE_global.h"
57 #include "BKE_main.h"
58 #include "BKE_scene.h"
59 #include "BKE_screen.h"
60 #include "BKE_utildefines.h"
61
62 #include "RE_pipeline.h"        // make_stars
63
64 #include "BIF_gl.h"
65
66 #include "WM_api.h"
67 #include "WM_types.h"
68
69 #include "ED_screen.h"
70
71 #include "UI_interface.h"
72 #include "UI_resources.h"
73 #include "UI_view2d.h"
74
75 #include "PIL_time.h" /* smoothview */
76
77 #include "view3d_intern.h"      // own include
78
79 #define BL_NEAR_CLIP 0.001
80
81
82
83 /* use this call when executing an operator,
84    event system doesn't set for each event the
85    opengl drawing context */
86 void view3d_operator_needs_opengl(const bContext *C)
87 {
88         ARegion *ar= CTX_wm_region(C);
89
90         /* for debugging purpose, context should always be OK */
91         if(ar->regiontype!=RGN_TYPE_WINDOW)
92                 printf("view3d_operator_needs_opengl error, wrong region\n");
93         else {
94                 ScrArea *sa= CTX_wm_area(C);
95                 View3D *v3d= sa->spacedata.first;
96                 
97                 wmSubWindowSet(CTX_wm_window(C), ar->swinid);
98                 glMatrixMode(GL_PROJECTION);
99                 wmLoadMatrix(v3d->winmat);
100                 glMatrixMode(GL_MODELVIEW);
101                 wmLoadMatrix(v3d->viewmat);
102         }
103 }
104
105 float *give_cursor(Scene *scene, View3D *v3d)
106 {
107         if(v3d && v3d->localview) return v3d->cursor;
108         else return scene->cursor;
109 }
110
111 /* ****************** smooth view operator ****************** */
112
113 struct SmoothViewStore {
114         float orig_dist, new_dist;
115         float orig_lens, new_lens;
116         float orig_quat[4], new_quat[4];
117         float orig_ofs[3], new_ofs[3];
118         
119         int to_camera, orig_view;
120         
121         double time_allowed;
122 };
123
124 /* will start timer if appropriate */
125 /* the arguments are the desired situation */
126 void smooth_view(bContext *C, Object *oldcamera, Object *camera, float *ofs, float *quat, float *dist, float *lens)
127 {
128         View3D *v3d= (View3D *)CTX_wm_space_data(C);
129         struct SmoothViewStore sms;
130         
131         /* initialize sms */
132         VECCOPY(sms.new_ofs, v3d->ofs);
133         QUATCOPY(sms.new_quat, v3d->viewquat);
134         sms.new_dist= v3d->dist;
135         sms.new_lens= v3d->lens;
136         sms.to_camera= 0;
137         
138         /* store the options we want to end with */
139         if(ofs) VECCOPY(sms.new_ofs, ofs);
140         if(quat) QUATCOPY(sms.new_quat, quat);
141         if(dist) sms.new_dist= *dist;
142         if(lens) sms.new_lens= *lens;
143         
144         if (camera) {
145                 view_settings_from_ob(camera, sms.new_ofs, sms.new_quat, &sms.new_dist, &sms.new_lens);
146                 sms.to_camera= 1; /* restore view3d values in end */
147         }
148         
149         if (C && U.smooth_viewtx) {
150                 int changed = 0; /* zero means no difference */
151                 
152                 if (sms.new_dist != v3d->dist)
153                         changed = 1;
154                 if (sms.new_lens != v3d->lens)
155                         changed = 1;
156                 
157                 if ((sms.new_ofs[0]!=v3d->ofs[0]) ||
158                         (sms.new_ofs[1]!=v3d->ofs[1]) ||
159                         (sms.new_ofs[2]!=v3d->ofs[2]) )
160                         changed = 1;
161                 
162                 if ((sms.new_quat[0]!=v3d->viewquat[0]) ||
163                         (sms.new_quat[1]!=v3d->viewquat[1]) ||
164                         (sms.new_quat[2]!=v3d->viewquat[2]) ||
165                         (sms.new_quat[3]!=v3d->viewquat[3]) )
166                         changed = 1;
167                 
168                 /* The new view is different from the old one
169                         * so animate the view */
170                 if (changed) {
171                         
172                         sms.time_allowed= (double)U.smooth_viewtx / 1000.0;
173                         
174                         /* if this is view rotation only
175                                 * we can decrease the time allowed by
176                                 * the angle between quats 
177                                 * this means small rotations wont lag */
178                         if (quat && !ofs && !dist) {
179                                 float vec1[3], vec2[3];
180                                 
181                                 VECCOPY(vec1, sms.new_quat);
182                                 VECCOPY(vec2, sms.orig_quat);
183                                 Normalize(vec1);
184                                 Normalize(vec2);
185                                 /* scale the time allowed by the rotation */
186                                 sms.time_allowed *= NormalizedVecAngle2(vec1, vec2)/(M_PI/2); 
187                         }
188                         
189                         /* original values */
190                         if (oldcamera) {
191                                 sms.orig_dist= v3d->dist; // below function does weird stuff with it...
192                                 view_settings_from_ob(oldcamera, sms.orig_ofs, sms.orig_quat, &sms.orig_dist, &sms.orig_lens);
193                         }
194                         else {
195                                 VECCOPY(sms.orig_ofs, v3d->ofs);
196                                 QUATCOPY(sms.orig_quat, v3d->viewquat);
197                                 sms.orig_dist= v3d->dist;
198                                 sms.orig_lens= v3d->lens;
199                         }
200                         /* grid draw as floor */
201                         sms.orig_view= v3d->view;
202                         v3d->view= 0;
203                         
204                         /* ensure it shows correct */
205                         if(sms.to_camera) v3d->persp= V3D_PERSP;
206                         
207                         /* keep track of running timer! */
208                         if(v3d->sms==NULL)
209                                 v3d->sms= MEM_mallocN(sizeof(struct SmoothViewStore), "smoothview v3d");
210                         *v3d->sms= sms;
211                         if(v3d->smooth_timer)
212                                 WM_event_remove_window_timer(CTX_wm_window(C), v3d->smooth_timer);
213                         /* TIMER1 is hardcoded in keymap */
214                         v3d->smooth_timer= WM_event_add_window_timer(CTX_wm_window(C), TIMER1, 1.0/30.0);       /* max 30 frs/sec */
215                         
216                         return;
217                 }
218         }
219         
220         /* if we get here nothing happens */
221         if(sms.to_camera==0) {
222                 VECCOPY(v3d->ofs, sms.new_ofs);
223                 QUATCOPY(v3d->viewquat, sms.new_quat);
224                 v3d->dist = sms.new_dist;
225                 v3d->lens = sms.new_lens;
226         }
227         ED_region_tag_redraw(CTX_wm_region(C));
228 }
229
230 /* only meant for timer usage */
231 static int view3d_smoothview_invoke(bContext *C, wmOperator *op, wmEvent *event)
232 {
233         View3D *v3d= (View3D *)CTX_wm_space_data(C);
234         struct SmoothViewStore *sms= v3d->sms;
235         double step, step_inv;
236         
237         /* escape if not our timer */
238         if(v3d->smooth_timer==NULL || v3d->smooth_timer!=event->customdata)
239                 return OPERATOR_PASS_THROUGH;
240         
241         step =  (v3d->smooth_timer->duration)/sms->time_allowed;
242         
243         /* end timer */
244         if(step >= 1.0f) {
245                 
246                 /* if we went to camera, store the original */
247                 if(sms->to_camera) {
248                         v3d->persp= V3D_CAMOB;
249                         VECCOPY(v3d->ofs, sms->orig_ofs);
250                         QUATCOPY(v3d->viewquat, sms->orig_quat);
251                         v3d->dist = sms->orig_dist;
252                         v3d->lens = sms->orig_lens;
253                 }
254                 else {
255                         VECCOPY(v3d->ofs, sms->new_ofs);
256                         QUATCOPY(v3d->viewquat, sms->new_quat);
257                         v3d->dist = sms->new_dist;
258                         v3d->lens = sms->new_lens;
259                 }
260                 v3d->view= sms->orig_view;
261                 
262                 MEM_freeN(v3d->sms);
263                 v3d->sms= NULL;
264                 
265                 WM_event_remove_window_timer(CTX_wm_window(C), v3d->smooth_timer);
266                 v3d->smooth_timer= NULL;
267         }
268         else {
269                 int i;
270                 
271                 /* ease in/out */
272                 if (step < 0.5) step = (float)pow(step*2, 2)/2;
273                 else                    step = (float)1-(pow(2*(1-step),2)/2);
274
275                 step_inv = 1.0-step;
276
277                 for (i=0; i<3; i++)
278                         v3d->ofs[i] = sms->new_ofs[i]*step + sms->orig_ofs[i]*step_inv;
279
280                 QuatInterpol(v3d->viewquat, sms->orig_quat, sms->new_quat, step);
281                 
282                 v3d->dist = sms->new_dist*step + sms->orig_dist*step_inv;
283                 v3d->lens = sms->new_lens*step + sms->orig_lens*step_inv;
284         }
285         
286         ED_region_tag_redraw(CTX_wm_region(C));
287         
288         return OPERATOR_FINISHED;
289 }
290
291 void VIEW3D_OT_smoothview(wmOperatorType *ot)
292 {
293         
294         /* identifiers */
295         ot->name= "Smooth View";
296         ot->idname= "VIEW3D_OT_smoothview";
297         
298         /* api callbacks */
299         ot->invoke= view3d_smoothview_invoke;
300         
301         ot->poll= ED_operator_areaactive;
302 }
303
304 /* ********************************** */
305
306 /* create intersection coordinates in view Z direction at mouse coordinates */
307 void viewline(ARegion *ar, View3D *v3d, short mval[2], float ray_start[3], float ray_end[3])
308 {
309         float vec[4];
310         
311         if(v3d->persp != V3D_ORTHO){
312                 vec[0]= 2.0f * mval[0] / ar->winx - 1;
313                 vec[1]= 2.0f * mval[1] / ar->winy - 1;
314                 vec[2]= -1.0f;
315                 vec[3]= 1.0f;
316                 
317                 Mat4MulVec4fl(v3d->persinv, vec);
318                 VecMulf(vec, 1.0f / vec[3]);
319                 
320                 VECCOPY(ray_start, v3d->viewinv[3]);
321                 VECSUB(vec, vec, ray_start);
322                 Normalize(vec);
323                 
324                 VECADDFAC(ray_start, v3d->viewinv[3], vec, v3d->near);
325                 VECADDFAC(ray_end, v3d->viewinv[3], vec, v3d->far);
326         }
327         else {
328                 vec[0] = 2.0f * mval[0] / ar->winx - 1;
329                 vec[1] = 2.0f * mval[1] / ar->winy - 1;
330                 vec[2] = 0.0f;
331                 vec[3] = 1.0f;
332                 
333                 Mat4MulVec4fl(v3d->persinv, vec);
334                 
335                 VECADDFAC(ray_start, vec, v3d->viewinv[2],  1000.0f);
336                 VECADDFAC(ray_end, vec, v3d->viewinv[2], -1000.0f);
337         }
338 }
339
340 /* create intersection ray in view Z direction at mouse coordinates */
341 void viewray(ARegion *ar, View3D *v3d, short mval[2], float ray_start[3], float ray_normal[3])
342 {
343         float ray_end[3];
344         
345         viewline(ar, v3d, mval, ray_start, ray_end);
346         VecSubf(ray_normal, ray_end, ray_start);
347         Normalize(ray_normal);
348 }
349
350
351 void initgrabz(View3D *v3d, float x, float y, float z)
352 {
353         if(v3d==NULL) return;
354         v3d->zfac= v3d->persmat[0][3]*x+ v3d->persmat[1][3]*y+ v3d->persmat[2][3]*z+ v3d->persmat[3][3];
355         
356         /* if x,y,z is exactly the viewport offset, zfac is 0 and we don't want that 
357                 * (accounting for near zero values)
358                 * */
359         if (v3d->zfac < 1.e-6f && v3d->zfac > -1.e-6f) v3d->zfac = 1.0f;
360         
361         /* Negative zfac means x, y, z was behind the camera (in perspective).
362                 * This gives flipped directions, so revert back to ok default case.
363         */
364         if (v3d->zfac < 0.0f) v3d->zfac = 1.0f;
365 }
366
367 void window_to_3d(ARegion *ar, View3D *v3d, float *vec, short mx, short my)
368 {
369         /* always call initgrabz */
370         float dx, dy;
371         
372         dx= 2.0f*mx*v3d->zfac/ar->winx;
373         dy= 2.0f*my*v3d->zfac/ar->winy;
374         
375         vec[0]= (v3d->persinv[0][0]*dx + v3d->persinv[1][0]*dy);
376         vec[1]= (v3d->persinv[0][1]*dx + v3d->persinv[1][1]*dy);
377         vec[2]= (v3d->persinv[0][2]*dx + v3d->persinv[1][2]*dy);
378 }
379
380 void view3d_get_object_project_mat(View3D *v3d, Object *ob, float pmat[4][4], float vmat[4][4])
381 {
382         Mat4MulMat4(vmat, ob->obmat, v3d->viewmat);
383         Mat4MulMat4(pmat, vmat, v3d->winmat);
384         Mat4CpyMat4(vmat, ob->obmat);
385 }
386
387 /* projectmat brings it to window coords, wmat to rotated world space */
388 void view3d_project_short_clip(ARegion *ar, View3D *v3d, float *vec, short *adr, float projmat[4][4], float wmat[4][4])
389 {
390         float fx, fy, vec4[4];
391         
392         adr[0]= IS_CLIPPED;
393         
394         /* clipplanes in eye space */
395         if(v3d->flag & V3D_CLIPPING) {
396                 VECCOPY(vec4, vec);
397                 Mat4MulVecfl(wmat, vec4);
398                 if(view3d_test_clipping(v3d, vec4))
399                         return;
400         }
401         
402         VECCOPY(vec4, vec);
403         vec4[3]= 1.0;
404         
405         Mat4MulVec4fl(projmat, vec4);
406         
407         /* clipplanes in window space */
408         if( vec4[3]>BL_NEAR_CLIP ) {    /* 0.001 is the NEAR clipping cutoff for picking */
409                 fx= (ar->winx/2)*(1 + vec4[0]/vec4[3]);
410                 
411                 if( fx>0 && fx<ar->winx) {
412                         
413                         fy= (ar->winy/2)*(1 + vec4[1]/vec4[3]);
414                         
415                         if(fy>0.0 && fy< (float)ar->winy) {
416                                 adr[0]= (short)floor(fx); 
417                                 adr[1]= (short)floor(fy);
418                         }
419                 }
420         }
421 }
422
423 void view3d_project_short_noclip(ARegion *ar, float *vec, short *adr, float mat[4][4])
424 {
425         float fx, fy, vec4[4];
426         
427         adr[0]= IS_CLIPPED;
428         
429         VECCOPY(vec4, vec);
430         vec4[3]= 1.0;
431         
432         Mat4MulVec4fl(mat, vec4);
433         
434         if( vec4[3]>BL_NEAR_CLIP ) {    /* 0.001 is the NEAR clipping cutoff for picking */
435                 fx= (ar->winx/2)*(1 + vec4[0]/vec4[3]);
436                 
437                 if( fx>-32700 && fx<32700) {
438                         
439                         fy= (ar->winy/2)*(1 + vec4[1]/vec4[3]);
440                         
441                         if(fy>-32700.0 && fy<32700.0) {
442                                 adr[0]= (short)floor(fx); 
443                                 adr[1]= (short)floor(fy);
444                         }
445                 }
446         }
447 }
448
449 void view3d_project_float(ARegion *ar, float *vec, float *adr, float mat[4][4])
450 {
451         float vec4[4];
452         
453         adr[0]= IS_CLIPPED;
454         VECCOPY(vec4, vec);
455         vec4[3]= 1.0;
456         
457         Mat4MulVec4fl(mat, vec4);
458         
459         if( vec4[3]>FLT_EPSILON ) {
460                 adr[0] = (float)(ar->winx/2.0f)+(ar->winx/2.0f)*vec4[0]/vec4[3];        
461                 adr[1] = (float)(ar->winy/2.0f)+(ar->winy/2.0f)*vec4[1]/vec4[3];
462         } else {
463                 adr[0] = adr[1] = 0.0f;
464         }
465 }
466
467 int boundbox_clip(View3D *v3d, float obmat[][4], BoundBox *bb)
468 {
469         /* return 1: draw */
470         
471         float mat[4][4];
472         float vec[4], min, max;
473         int a, flag= -1, fl;
474         
475         if(bb==NULL) return 1;
476         if(bb->flag & OB_BB_DISABLED) return 1;
477         
478         Mat4MulMat4(mat, obmat, v3d->persmat);
479         
480         for(a=0; a<8; a++) {
481                 VECCOPY(vec, bb->vec[a]);
482                 vec[3]= 1.0;
483                 Mat4MulVec4fl(mat, vec);
484                 max= vec[3];
485                 min= -vec[3];
486                 
487                 fl= 0;
488                 if(vec[0] < min) fl+= 1;
489                 if(vec[0] > max) fl+= 2;
490                 if(vec[1] < min) fl+= 4;
491                 if(vec[1] > max) fl+= 8;
492                 if(vec[2] < min) fl+= 16;
493                 if(vec[2] > max) fl+= 32;
494                 
495                 flag &= fl;
496                 if(flag==0) return 1;
497         }
498         
499         return 0;
500 }
501
502 void project_short(ARegion *ar, View3D *v3d, float *vec, short *adr)    /* clips */
503 {
504         float fx, fy, vec4[4];
505         
506         adr[0]= IS_CLIPPED;
507         
508         if(v3d->flag & V3D_CLIPPING) {
509                 if(view3d_test_clipping(v3d, vec))
510                         return;
511         }
512         
513         VECCOPY(vec4, vec);
514         vec4[3]= 1.0;
515         Mat4MulVec4fl(v3d->persmat, vec4);
516         
517         if( vec4[3]>BL_NEAR_CLIP ) {    /* 0.001 is the NEAR clipping cutoff for picking */
518                 fx= (ar->winx/2)*(1 + vec4[0]/vec4[3]);
519                 
520                 if( fx>0 && fx<ar->winx) {
521                         
522                         fy= (ar->winy/2)*(1 + vec4[1]/vec4[3]);
523                         
524                         if(fy>0.0 && fy< (float)ar->winy) {
525                                 adr[0]= (short)floor(fx); 
526                                 adr[1]= (short)floor(fy);
527                         }
528                 }
529         }
530 }
531
532 void project_int(ARegion *ar, View3D *v3d, float *vec, int *adr)
533 {
534         float fx, fy, vec4[4];
535         
536         adr[0]= (int)2140000000.0f;
537         VECCOPY(vec4, vec);
538         vec4[3]= 1.0;
539         
540         Mat4MulVec4fl(v3d->persmat, vec4);
541         
542         if( vec4[3]>BL_NEAR_CLIP ) {    /* 0.001 is the NEAR clipping cutoff for picking */
543                 fx= (ar->winx/2)*(1 + vec4[0]/vec4[3]);
544                 
545                 if( fx>-2140000000.0f && fx<2140000000.0f) {
546                         fy= (ar->winy/2)*(1 + vec4[1]/vec4[3]);
547                         
548                         if(fy>-2140000000.0f && fy<2140000000.0f) {
549                                 adr[0]= (int)floor(fx); 
550                                 adr[1]= (int)floor(fy);
551                         }
552                 }
553         }
554 }
555
556 void project_int_noclip(ARegion *ar, View3D *v3d, float *vec, int *adr)
557 {
558         float fx, fy, vec4[4];
559         
560         VECCOPY(vec4, vec);
561         vec4[3]= 1.0;
562         
563         Mat4MulVec4fl(v3d->persmat, vec4);
564         
565         if( fabs(vec4[3]) > BL_NEAR_CLIP ) {
566                 fx = (ar->winx/2)*(1 + vec4[0]/vec4[3]);
567                 fy = (ar->winy/2)*(1 + vec4[1]/vec4[3]);
568                 
569                 adr[0] = (int)floor(fx); 
570                 adr[1] = (int)floor(fy);
571         }
572         else
573         {
574                 adr[0] = ar->winx / 2;
575                 adr[1] = ar->winy / 2;
576         }
577 }
578
579 void project_short_noclip(ARegion *ar, View3D *v3d, float *vec, short *adr)
580 {
581         float fx, fy, vec4[4];
582         
583         adr[0]= IS_CLIPPED;
584         VECCOPY(vec4, vec);
585         vec4[3]= 1.0;
586         
587         Mat4MulVec4fl(v3d->persmat, vec4);
588         
589         if( vec4[3]>BL_NEAR_CLIP ) {    /* 0.001 is the NEAR clipping cutoff for picking */
590                 fx= (ar->winx/2)*(1 + vec4[0]/vec4[3]);
591                 
592                 if( fx>-32700 && fx<32700) {
593                         
594                         fy= (ar->winy/2)*(1 + vec4[1]/vec4[3]);
595                         
596                         if(fy>-32700.0 && fy<32700.0) {
597                                 adr[0]= (short)floor(fx); 
598                                 adr[1]= (short)floor(fy);
599                         }
600                 }
601         }
602 }
603
604 void project_float(ARegion *ar, View3D *v3d, float *vec, float *adr)
605 {
606         float vec4[4];
607         
608         adr[0]= IS_CLIPPED;
609         VECCOPY(vec4, vec);
610         vec4[3]= 1.0;
611         
612         Mat4MulVec4fl(v3d->persmat, vec4);
613         
614         if( vec4[3]>BL_NEAR_CLIP ) {
615                 adr[0] = (float)(ar->winx/2.0)+(ar->winx/2.0)*vec4[0]/vec4[3];  
616                 adr[1] = (float)(ar->winy/2.0)+(ar->winy/2.0)*vec4[1]/vec4[3];
617         }
618 }
619
620 void project_float_noclip(ARegion *ar, View3D *v3d, float *vec, float *adr)
621 {
622         float vec4[4];
623         
624         VECCOPY(vec4, vec);
625         vec4[3]= 1.0;
626         
627         Mat4MulVec4fl(v3d->persmat, vec4);
628         
629         if( fabs(vec4[3]) > BL_NEAR_CLIP ) {
630                 adr[0] = (float)(ar->winx/2.0)+(ar->winx/2.0)*vec4[0]/vec4[3];  
631                 adr[1] = (float)(ar->winy/2.0)+(ar->winy/2.0)*vec4[1]/vec4[3];
632         }
633         else
634         {
635                 adr[0] = ar->winx / 2.0f;
636                 adr[1] = ar->winy / 2.0f;
637         }
638 }
639
640
641
642 /* also exposed in previewrender.c */
643 int get_view3d_viewplane(View3D *v3d, int winxi, int winyi, rctf *viewplane, float *clipsta, float *clipend, float *pixsize)
644 {
645         Camera *cam=NULL;
646         float lens, fac, x1, y1, x2, y2;
647         float winx= (float)winxi, winy= (float)winyi;
648         int orth= 0;
649         
650         lens= v3d->lens;        
651         
652         *clipsta= v3d->near;
653         *clipend= v3d->far;
654         
655         if(v3d->persp==V3D_CAMOB) {
656                 if(v3d->camera) {
657                         if(v3d->camera->type==OB_LAMP ) {
658                                 Lamp *la;
659                                 
660                                 la= v3d->camera->data;
661                                 fac= cos( M_PI*la->spotsize/360.0);
662                                 
663                                 x1= saacos(fac);
664                                 lens= 16.0*fac/sin(x1);
665                                 
666                                 *clipsta= la->clipsta;
667                                 *clipend= la->clipend;
668                         }
669                         else if(v3d->camera->type==OB_CAMERA) {
670                                 cam= v3d->camera->data;
671                                 lens= cam->lens;
672                                 *clipsta= cam->clipsta;
673                                 *clipend= cam->clipend;
674                         }
675                 }
676         }
677         
678         if(v3d->persp==V3D_ORTHO) {
679                 if(winx>winy) x1= -v3d->dist;
680                 else x1= -winx*v3d->dist/winy;
681                 x2= -x1;
682                 
683                 if(winx>winy) y1= -winy*v3d->dist/winx;
684                 else y1= -v3d->dist;
685                 y2= -y1;
686                 
687                 *clipend *= 0.5;        // otherwise too extreme low zbuffer quality
688                 *clipsta= - *clipend;
689                 orth= 1;
690         }
691         else {
692                 /* fac for zoom, also used for camdx */
693                 if(v3d->persp==V3D_CAMOB) {
694                         fac= (1.41421+( (float)v3d->camzoom )/50.0);
695                         fac*= fac;
696                 }
697                 else fac= 2.0;
698                 
699                 /* viewplane size depends... */
700                 if(cam && cam->type==CAM_ORTHO) {
701                         /* ortho_scale == 1 means exact 1 to 1 mapping */
702                         float dfac= 2.0*cam->ortho_scale/fac;
703                         
704                         if(winx>winy) x1= -dfac;
705                         else x1= -winx*dfac/winy;
706                         x2= -x1;
707                         
708                         if(winx>winy) y1= -winy*dfac/winx;
709                         else y1= -dfac;
710                         y2= -y1;
711                         orth= 1;
712                 }
713                 else {
714                         float dfac;
715                         
716                         if(winx>winy) dfac= 64.0/(fac*winx*lens);
717                         else dfac= 64.0/(fac*winy*lens);
718                         
719                         x1= - *clipsta * winx*dfac;
720                         x2= -x1;
721                         y1= - *clipsta * winy*dfac;
722                         y2= -y1;
723                         orth= 0;
724                 }
725                 /* cam view offset */
726                 if(cam) {
727                         float dx= 0.5*fac*v3d->camdx*(x2-x1);
728                         float dy= 0.5*fac*v3d->camdy*(y2-y1);
729                         x1+= dx;
730                         x2+= dx;
731                         y1+= dy;
732                         y2+= dy;
733                 }
734         }
735         
736         if(pixsize) {
737                 float viewfac;
738                 
739                 if(orth) {
740                         viewfac= (winx >= winy)? winx: winy;
741                         *pixsize= 1.0f/viewfac;
742                 }
743                 else {
744                         viewfac= (((winx >= winy)? winx: winy)*lens)/32.0;
745                         *pixsize= *clipsta/viewfac;
746                 }
747         }
748         
749         viewplane->xmin= x1;
750         viewplane->ymin= y1;
751         viewplane->xmax= x2;
752         viewplane->ymax= y2;
753         
754         return orth;
755 }
756
757
758 /* important to not set windows active in here, can be renderwin for example */
759 void setwinmatrixview3d(View3D *v3d, int winx, int winy, rctf *rect)            /* rect: for picking */
760 {
761         rctf viewplane;
762         float clipsta, clipend, x1, y1, x2, y2;
763         int orth;
764         
765         orth= get_view3d_viewplane(v3d, winx, winy, &viewplane, &clipsta, &clipend, NULL);
766         //      printf("%d %d %f %f %f %f %f %f\n", winx, winy, viewplane.xmin, viewplane.ymin, viewplane.xmax, viewplane.ymax, clipsta, clipend);
767         x1= viewplane.xmin;
768         y1= viewplane.ymin;
769         x2= viewplane.xmax;
770         y2= viewplane.ymax;
771         
772         if(rect) {              /* picking */
773                 rect->xmin/= (float)winx;
774                 rect->xmin= x1+rect->xmin*(x2-x1);
775                 rect->ymin/= (float)winy;
776                 rect->ymin= y1+rect->ymin*(y2-y1);
777                 rect->xmax/= (float)winx;
778                 rect->xmax= x1+rect->xmax*(x2-x1);
779                 rect->ymax/= (float)winy;
780                 rect->ymax= y1+rect->ymax*(y2-y1);
781                 
782                 if(orth) wmOrtho(rect->xmin, rect->xmax, rect->ymin, rect->ymax, -clipend, clipend);
783                 else wmFrustum(rect->xmin, rect->xmax, rect->ymin, rect->ymax, clipsta, clipend);
784                 
785         }
786         else {
787                 if(orth) wmOrtho(x1, x2, y1, y2, clipsta, clipend);
788                 else wmFrustum(x1, x2, y1, y2, clipsta, clipend);
789         }
790
791         /* not sure what this was for? (ton) */
792         glMatrixMode(GL_PROJECTION);
793         wmGetMatrix(v3d->winmat);
794         glMatrixMode(GL_MODELVIEW);
795 }
796
797
798
799 /* Gets the lens and clipping values from a camera of lamp type object */
800 static void object_lens_clip_settings(Object *ob, float *lens, float *clipsta, float *clipend)
801 {       
802         if (!ob) return;
803         
804         if(ob->type==OB_LAMP ) {
805                 Lamp *la = ob->data;
806                 if (lens) {
807                         float x1, fac;
808                         fac= cos( M_PI*la->spotsize/360.0);
809                         x1= saacos(fac);
810                         *lens= 16.0*fac/sin(x1);
811                 }
812                 if (clipsta)    *clipsta= la->clipsta;
813                 if (clipend)    *clipend= la->clipend;
814         }
815         else if(ob->type==OB_CAMERA) {
816                 Camera *cam= ob->data;
817                 if (lens)               *lens= cam->lens;
818                 if (clipsta)    *clipsta= cam->clipsta;
819                 if (clipend)    *clipend= cam->clipend;
820         }
821         else {
822                 if (lens)               *lens= 35.0f;
823         }
824 }
825
826
827 /* Gets the view trasnformation from a camera
828 * currently dosnt take camzoom into account
829
830 * The dist is not modified for this function, if NULL its assimed zero
831 * */
832 void view_settings_from_ob(Object *ob, float *ofs, float *quat, float *dist, float *lens)
833 {       
834         float bmat[4][4];
835         float imat[4][4];
836         float tmat[3][3];
837         
838         if (!ob) return;
839         
840         /* Offset */
841         if (ofs) {
842                 where_is_object(ob);
843                 VECCOPY(ofs, ob->obmat[3]);
844                 VecMulf(ofs, -1.0f); /*flip the vector*/
845         }
846         
847         /* Quat */
848         if (quat) {
849                 Mat4CpyMat4(bmat, ob->obmat);
850                 Mat4Ortho(bmat);
851                 Mat4Invert(imat, bmat);
852                 Mat3CpyMat4(tmat, imat);
853                 Mat3ToQuat(tmat, quat);
854         }
855         
856         if (dist) {
857                 float vec[3];
858                 Mat3CpyMat4(tmat, ob->obmat);
859                 
860                 vec[0]= vec[1] = 0.0;
861                 vec[2]= -(*dist);
862                 Mat3MulVecfl(tmat, vec);
863                 VecSubf(ofs, ofs, vec);
864         }
865         
866         /* Lens */
867         if (lens)
868                 object_lens_clip_settings(ob, lens, NULL, NULL);
869 }
870
871
872 void obmat_to_viewmat(View3D *v3d, Object *ob, short smooth)
873 {
874         float bmat[4][4];
875         float tmat[3][3];
876         
877         v3d->view= 0; /* dont show the grid */
878         
879         Mat4CpyMat4(bmat, ob->obmat);
880         Mat4Ortho(bmat);
881         Mat4Invert(v3d->viewmat, bmat);
882         
883         /* view quat calculation, needed for add object */
884         Mat3CpyMat4(tmat, v3d->viewmat);
885         if (smooth) {
886                 float new_quat[4];
887                 if (v3d->persp==V3D_CAMOB && v3d->camera) {
888                         /* were from a camera view */
889                         
890                         float orig_ofs[3];
891                         float orig_dist= v3d->dist;
892                         float orig_lens= v3d->lens;
893                         VECCOPY(orig_ofs, v3d->ofs);
894                         
895                         /* Switch from camera view */
896                         Mat3ToQuat(tmat, new_quat);
897                         
898                         v3d->persp=V3D_PERSP;
899                         v3d->dist= 0.0;
900                         
901                         view_settings_from_ob(v3d->camera, v3d->ofs, NULL, NULL, &v3d->lens);
902                         smooth_view(NULL, NULL, NULL, orig_ofs, new_quat, &orig_dist, &orig_lens); // XXX
903                         
904                         v3d->persp=V3D_CAMOB; /* just to be polite, not needed */
905                         
906                 } else {
907                         Mat3ToQuat(tmat, new_quat);
908                         smooth_view(NULL, NULL, NULL, NULL, new_quat, NULL, NULL); // XXX
909                 }
910         } else {
911                 Mat3ToQuat(tmat, v3d->viewquat);
912         }
913 }
914
915 /* dont set windows active in in here, is used by renderwin too */
916 void setviewmatrixview3d(View3D *v3d)
917 {
918         if(v3d->persp==V3D_CAMOB) {         /* obs/camera */
919                 if(v3d->camera) {
920                         where_is_object(v3d->camera);   
921                         obmat_to_viewmat(v3d, v3d->camera, 0);
922                 }
923                 else {
924                         QuatToMat4(v3d->viewquat, v3d->viewmat);
925                         v3d->viewmat[3][2]-= v3d->dist;
926                 }
927         }
928         else {
929                 
930                 QuatToMat4(v3d->viewquat, v3d->viewmat);
931                 if(v3d->persp==V3D_PERSP) v3d->viewmat[3][2]-= v3d->dist;
932                 if(v3d->ob_centre) {
933                         Object *ob= v3d->ob_centre;
934                         float vec[3];
935                         
936                         VECCOPY(vec, ob->obmat[3]);
937                         if(ob->type==OB_ARMATURE && v3d->ob_centre_bone[0]) {
938                                 bPoseChannel *pchan= get_pose_channel(ob->pose, v3d->ob_centre_bone);
939                                 if(pchan) {
940                                         VECCOPY(vec, pchan->pose_mat[3]);
941                                         Mat4MulVecfl(ob->obmat, vec);
942                                 }
943                         }
944                         i_translate(-vec[0], -vec[1], -vec[2], v3d->viewmat);
945                 }
946                 else i_translate(v3d->ofs[0], v3d->ofs[1], v3d->ofs[2], v3d->viewmat);
947         }
948 }
949
950 void setcameratoview3d(View3D *v3d)
951 {
952         Object *ob;
953         float dvec[3];
954         
955         ob= v3d->camera;
956         dvec[0]= v3d->dist*v3d->viewinv[2][0];
957         dvec[1]= v3d->dist*v3d->viewinv[2][1];
958         dvec[2]= v3d->dist*v3d->viewinv[2][2];                                  
959         VECCOPY(ob->loc, dvec);
960         VecSubf(ob->loc, ob->loc, v3d->ofs);
961         v3d->viewquat[0]= -v3d->viewquat[0];
962         /*  */
963         /*if (ob->transflag & OB_QUAT) {
964                 QUATCOPY(ob->quat, v3d->viewquat);
965         } else {*/
966         QuatToEul(v3d->viewquat, ob->rot);
967         /*}*/
968         v3d->viewquat[0]= -v3d->viewquat[0];
969 }
970
971
972 /* IGLuint-> GLuint*/
973 /* Warning: be sure to account for a negative return value
974 *   This is an error, "Too many objects in select buffer"
975 *   and no action should be taken (can crash blender) if this happens
976 */
977 short view3d_opengl_select(Scene *scene, ARegion *ar, View3D *v3d, unsigned int *buffer, unsigned int bufsize, rcti *input)
978 {
979         rctf rect;
980         short code, hits;
981         
982         G.f |= G_PICKSEL;
983         
984         /* case not a border select */
985         if(input->xmin==input->xmax) {
986                 rect.xmin= input->xmin-12;      // seems to be default value for bones only now
987                 rect.xmax= input->xmin+12;
988                 rect.ymin= input->ymin-12;
989                 rect.ymax= input->xmin+12;
990         }
991         else {
992                 rect.xmin= input->xmin;
993                 rect.xmax= input->xmax;
994                 rect.ymin= input->ymin;
995                 rect.ymax= input->ymax;
996         }
997         
998         setwinmatrixview3d(v3d, ar->winx, ar->winy, &rect);
999         Mat4MulMat4(v3d->persmat, v3d->viewmat, v3d->winmat);
1000         
1001         if(v3d->drawtype > OB_WIRE) {
1002                 v3d->zbuf= TRUE;
1003                 glEnable(GL_DEPTH_TEST);
1004         }
1005         
1006         if(v3d->flag & V3D_CLIPPING)
1007                 view3d_set_clipping(v3d);
1008         
1009         glSelectBuffer( bufsize, (GLuint *)buffer);
1010         glRenderMode(GL_SELECT);
1011         glInitNames();  /* these two calls whatfor? It doesnt work otherwise */
1012         glPushName(-1);
1013         code= 1;
1014         
1015         if(G.obedit && G.obedit->type==OB_MBALL) {
1016                 draw_object(scene, ar, v3d, BASACT, DRAW_PICKING|DRAW_CONSTCOLOR);
1017         }
1018         else if ((G.obedit && G.obedit->type==OB_ARMATURE)) {
1019                 draw_object(scene, ar, v3d, BASACT, DRAW_PICKING|DRAW_CONSTCOLOR);
1020         }
1021         else {
1022                 Base *base;
1023                 
1024                 v3d->xray= TRUE;        // otherwise it postpones drawing
1025                 for(base= scene->base.first; base; base= base->next) {
1026                         if(base->lay & v3d->lay) {
1027                                 
1028                                 if (base->object->restrictflag & OB_RESTRICT_SELECT)
1029                                         base->selcol= 0;
1030                                 else {
1031                                         base->selcol= code;
1032                                         glLoadName(code);
1033                                         draw_object(scene, ar, v3d, base, DRAW_PICKING|DRAW_CONSTCOLOR);
1034                                         
1035                                         /* we draw group-duplicators for selection too */
1036                                         if((base->object->transflag & OB_DUPLI) && base->object->dup_group) {
1037                                                 ListBase *lb;
1038                                                 DupliObject *dob;
1039                                                 Base tbase;
1040                                                 
1041                                                 tbase.flag= OB_FROMDUPLI;
1042                                                 lb= object_duplilist(scene, base->object);
1043                                                 
1044                                                 for(dob= lb->first; dob; dob= dob->next) {
1045                                                         tbase.object= dob->ob;
1046                                                         Mat4CpyMat4(dob->ob->obmat, dob->mat);
1047                                                         
1048                                                         draw_object(scene, ar, v3d, &tbase, DRAW_PICKING|DRAW_CONSTCOLOR);
1049                                                         
1050                                                         Mat4CpyMat4(dob->ob->obmat, dob->omat);
1051                                                 }
1052                                                 free_object_duplilist(lb);
1053                                         }
1054                                         code++;
1055                                 }                               
1056                         }
1057                 }
1058                 v3d->xray= FALSE;       // restore
1059         }
1060         
1061         glPopName();    /* see above (pushname) */
1062         hits= glRenderMode(GL_RENDER);
1063         
1064         G.f &= ~G_PICKSEL;
1065         setwinmatrixview3d(v3d, ar->winx, ar->winy, NULL);
1066         Mat4MulMat4(v3d->persmat, v3d->viewmat, v3d->winmat);
1067         
1068         if(v3d->drawtype > OB_WIRE) {
1069                 v3d->zbuf= 0;
1070                 glDisable(GL_DEPTH_TEST);
1071         }
1072 // XXX  persp(PERSP_WIN);
1073         
1074         if(v3d->flag & V3D_CLIPPING)
1075                 view3d_clr_clipping();
1076         
1077         if(hits<0) printf("Too many objects in select buffer\n");       // XXX make error message
1078         
1079         return hits;
1080 }
1081
1082 // XXX solve: localview on region level? no.... layers are area, so all regions in area have to be set
1083 static unsigned int free_localbit(void)
1084 {
1085         unsigned int lay;
1086         ScrArea *sa;
1087         bScreen *sc;
1088         
1089         lay= 0;
1090         
1091         /* sometimes we loose a localview: when an area is closed */
1092         /* check all areas: which localviews are in use? */
1093         for(sc= G.main->screen.first; sc; sc= sc->id.next) {
1094                 for(sa= sc->areabase.first; sa; sa= sa->next) {
1095                         SpaceLink *sl= sa->spacedata.first;
1096                         for(; sl; sl= sl->next) {
1097                                 if(sl->spacetype==SPACE_VIEW3D) {
1098                                         View3D *v3d= (View3D*) sl;
1099                                         lay |= v3d->lay;
1100                                 }
1101                         }
1102                 }
1103         }
1104         
1105         if( (lay & 0x01000000)==0) return 0x01000000;
1106         if( (lay & 0x02000000)==0) return 0x02000000;
1107         if( (lay & 0x04000000)==0) return 0x04000000;
1108         if( (lay & 0x08000000)==0) return 0x08000000;
1109         if( (lay & 0x10000000)==0) return 0x10000000;
1110         if( (lay & 0x20000000)==0) return 0x20000000;
1111         if( (lay & 0x40000000)==0) return 0x40000000;
1112         if( (lay & 0x80000000)==0) return 0x80000000;
1113         
1114         return 0;
1115 }
1116
1117
1118 void initlocalview(Scene *scene, ARegion *ar, View3D *v3d)
1119 {
1120         Base *base;
1121         float size = 0.0, min[3], max[3], afm[3];
1122         unsigned int locallay;
1123         int ok=0;
1124
1125         if(v3d->localvd) return;
1126
1127         INIT_MINMAX(min, max);
1128
1129         locallay= free_localbit();
1130
1131         if(locallay==0) {
1132                 printf("Sorry,  no more than 8 localviews\n");  // XXX error 
1133                 ok= 0;
1134         }
1135         else {
1136                 if(G.obedit) {
1137                         minmax_object(G.obedit, min, max);
1138                         
1139                         ok= 1;
1140                 
1141                         BASACT->lay |= locallay;
1142                         G.obedit->lay= BASACT->lay;
1143                 }
1144                 else {
1145                         base= FIRSTBASE;
1146                         while(base) {
1147                                 if(TESTBASE(v3d, base))  {
1148                                         minmax_object(base->object, min, max);
1149                                         base->lay |= locallay;
1150                                         base->object->lay= base->lay;
1151                                         ok= 1;
1152                                 }
1153                                 base= base->next;
1154                         }
1155                 }
1156                 
1157                 afm[0]= (max[0]-min[0]);
1158                 afm[1]= (max[1]-min[1]);
1159                 afm[2]= (max[2]-min[2]);
1160                 size= 0.7*MAX3(afm[0], afm[1], afm[2]);
1161                 if(size<=0.01) size= 0.01;
1162         }
1163         
1164         if(ok) {
1165                 v3d->localvd= MEM_mallocN(sizeof(View3D), "localview");
1166                 memcpy(v3d->localvd, v3d, sizeof(View3D));
1167
1168                 v3d->ofs[0]= -(min[0]+max[0])/2.0;
1169                 v3d->ofs[1]= -(min[1]+max[1])/2.0;
1170                 v3d->ofs[2]= -(min[2]+max[2])/2.0;
1171
1172                 v3d->dist= size;
1173
1174                 // correction for window aspect ratio
1175                 if(ar->winy>2 && ar->winx>2) {
1176                         size= (float)ar->winx/(float)ar->winy;
1177                         if(size<1.0) size= 1.0/size;
1178                         v3d->dist*= size;
1179                 }
1180                 
1181                 if (v3d->persp==V3D_CAMOB) v3d->persp= V3D_PERSP;
1182                 if (v3d->near> 0.1) v3d->near= 0.1;
1183                 
1184                 v3d->cursor[0]= -v3d->ofs[0];
1185                 v3d->cursor[1]= -v3d->ofs[1];
1186                 v3d->cursor[2]= -v3d->ofs[2];
1187
1188                 v3d->lay= locallay;
1189                 
1190 // XXX          countall();
1191 // XXX          scrarea_queue_winredraw(curarea);
1192         }
1193         else {
1194                 /* clear flags */ 
1195                 base= FIRSTBASE;
1196                 while(base) {
1197                         if( base->lay & locallay ) {
1198                                 base->lay-= locallay;
1199                                 if(base->lay==0) base->lay= v3d->layact;
1200                                 if(base->object != G.obedit) base->flag |= SELECT;
1201                                 base->object->lay= base->lay;
1202                         }
1203                         base= base->next;
1204                 }
1205 // XXX          scrarea_queue_headredraw(curarea);
1206                 
1207                 v3d->localview= 0;
1208         }
1209 // XXX  BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
1210 }
1211
1212 void restore_localviewdata(View3D *vd)
1213 {
1214         if(vd->localvd==0) return;
1215         
1216         VECCOPY(vd->ofs, vd->localvd->ofs);
1217         vd->dist= vd->localvd->dist;
1218         vd->persp= vd->localvd->persp;
1219         vd->view= vd->localvd->view;
1220         vd->near= vd->localvd->near;
1221         vd->far= vd->localvd->far;
1222         vd->lay= vd->localvd->lay;
1223         vd->layact= vd->localvd->layact;
1224         vd->drawtype= vd->localvd->drawtype;
1225         vd->camera= vd->localvd->camera;
1226         QUATCOPY(vd->viewquat, vd->localvd->viewquat);
1227         
1228 }
1229
1230 void endlocalview(Scene *scene, ScrArea *sa)
1231 {
1232         View3D *v3d;
1233         struct Base *base;
1234         unsigned int locallay;
1235         
1236         if(sa->spacetype!=SPACE_VIEW3D) return;
1237         v3d= sa->spacedata.first;
1238         
1239         if(v3d->localvd) {
1240                 
1241                 locallay= v3d->lay & 0xFF000000;
1242                 
1243                 restore_localviewdata(v3d);
1244                 
1245                 MEM_freeN(v3d->localvd);
1246                 v3d->localvd= 0;
1247                 v3d->localview= 0;
1248
1249                 /* for when in other window the layers have changed */
1250                 if(v3d->scenelock) v3d->lay= scene->lay;
1251                 
1252                 base= FIRSTBASE;
1253                 while(base) {
1254                         if( base->lay & locallay ) {
1255                                 base->lay-= locallay;
1256                                 if(base->lay==0) base->lay= v3d->layact;
1257                                 if(base->object != G.obedit) {
1258                                         base->flag |= SELECT;
1259                                         base->object->flag |= SELECT;
1260                                 }
1261                                 base->object->lay= base->lay;
1262                         }
1263                         base= base->next;
1264                 }
1265
1266 // XXX          countall();
1267 // XXX          allqueue(REDRAWVIEW3D, 0);      /* because of select */
1268 // XXX          allqueue(REDRAWOOPS, 0);        /* because of select */
1269 // XXX          BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
1270         } 
1271 }
1272
1273 void view3d_align_axis_to_vector(View3D *v3d, int axisidx, float vec[3])
1274 {
1275         float alignaxis[3] = {0.0, 0.0, 0.0};
1276         float norm[3], axis[3], angle, new_quat[4];
1277         
1278         if(axisidx > 0) alignaxis[axisidx-1]= 1.0;
1279         else alignaxis[-axisidx-1]= -1.0;
1280         
1281         VECCOPY(norm, vec);
1282         Normalize(norm);
1283         
1284         angle= (float)acos(Inpf(alignaxis, norm));
1285         Crossf(axis, alignaxis, norm);
1286         VecRotToQuat(axis, -angle, new_quat);
1287         
1288         v3d->view= 0;
1289         
1290         if (v3d->persp==V3D_CAMOB && v3d->camera) {
1291                 /* switch out of camera view */
1292                 float orig_ofs[3];
1293                 float orig_dist= v3d->dist;
1294                 float orig_lens= v3d->lens;
1295                 
1296                 VECCOPY(orig_ofs, v3d->ofs);
1297                 v3d->persp= V3D_PERSP;
1298                 v3d->dist= 0.0;
1299                 view_settings_from_ob(v3d->camera, v3d->ofs, NULL, NULL, &v3d->lens);
1300                 smooth_view(NULL, NULL, NULL, orig_ofs, new_quat, &orig_dist, &orig_lens); // XXX
1301         } else {
1302                 if (v3d->persp==V3D_CAMOB) v3d->persp= V3D_PERSP; /* switch out of camera mode */
1303                 smooth_view(NULL, NULL, NULL, NULL, new_quat, NULL, NULL); // XXX
1304         }
1305 }
1306