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